标签:
题意:给定一幅图的连接情况,给出每个点的权值,四种操作:
1 x y 连接x、y所在子树;
2 x y 将同一棵树上的x,y分离,形成两棵子树;
3 w x y 将x、y之间路径上的所有点权加w;
4 x y 查询x、y路径上点权的最大值;
动态树学习参考:http://www.cnblogs.com/BLADEVIL/p/3510997.html
http://wenku.baidu.com/view/75906f160b4e767f5acfcedb
http://m.blog.csdn.net/blog/wyfcyx_forever/39740335
思路:动态树解决树的合并分离操作,一般采用树链剖分与Splay tree结合;主要是splay方法,用到划分轻重链的思想;
初始时未建树,通过每次操作,划分轻重链并建splay树,访问到的链作为重链;
以access操作为核心,将当前点到根的路径变为一条重链并用splay维护,相当于变为一棵splay树;
由于用splay维护,合并操作在每次将u变为根节点后与v连接,分割操作在每次将u,v分别旋转至根和靠近根后删除边;
修改值和查找最大值通过lca找到路径中的根,然后分治到子区间求解;
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=300010; int ch[maxn][2],pre[maxn],key[maxn]; int add[maxn],rev[maxn],Max[maxn]; bool rt[maxn]; void update_add(int r,int d){ if(!r) return; key[r]+=d; add[r]+=d; Max[r]+=d; } void update_rev(int r){ if(!r) return; swap(ch[r][0],ch[r][1]); rev[r]^=1; } void pushdown(int r){ if(add[r]){ update_add(ch[r][0],add[r]); update_add(ch[r][1],add[r]); add[r]=0; } if(rev[r]){ update_rev(ch[r][0]); update_rev(ch[r][1]); rev[r]=0; } } void pushup(int r){ Max[r]=max(max(Max[ch[r][0]],Max[ch[r][1]]),key[r]); } void Rotate(int x){ int y=pre[x],kind=ch[y][1]==x; ch[y][kind]=ch[x][!kind]; pre[ch[y][kind]]=y; pre[x]=pre[y]; pre[y]=x; ch[x][!kind]=y; if(rt[y]){ rt[y]=false;rt[x]=true; } else{ ch[pre[x]][ch[pre[x]][1]==y]=x; } pushup(y); } void P(int r){ if(!rt[r]) P(pre[r]); pushdown(r); } void splay(int r){ P(r); while(!rt[r]){ int f=pre[r],ff=pre[f]; if(rt[f]) Rotate(r); else if((ch[ff][1]==f)==(ch[f][1]==r)) Rotate(f),Rotate(r); else Rotate(r),Rotate(r); } pushup(r); } int Access(int x){ //构造重链,用splay维护 int y=0; for(;x;x=pre[y=x]){ splay(x); rt[ch[x][1]]=true;rt[ch[x][1]=y]=false; pushup(x); } return y; } bool judge(int u,int v){ while(pre[u]) u=pre[u]; while(pre[v]) v=pre[v]; return u==v; } void mroot(int r){ Access(r); splay(r); update_rev(r); } void lca(int &u,int &v) { Access(v),v=0; while(u){ splay(u); if(!pre[u]) return; rt[ch[u][1]]=true; rt[ch[u][1]=v]=false; pushup(u); u=pre[v=u]; } } void link(int u,int v){ //合并 if(judge(u,v)){ puts("-1");return; } mroot(u); pre[u]=v; } void cut(int u,int v){ //分离 if(u==v||!judge(u,v)){ puts("-1");return; } mroot(u); splay(v); pre[ch[v][0]]=pre[v]; pre[v]=0; rt[ch[v][0]]=true; ch[v][0]=0; pushup(v); } void ADD(int u,int v,int w){ if(!judge(u,v)){ puts("-1"); return; } lca(u,v); update_add(ch[u][1],w); update_add(v,w); key[u]+=w; pushup(u); } void query(int u,int v){ if(!judge(u,v)){ puts("-1");return; } lca(u,v); printf("%d\n",max(max(Max[v],Max[ch[u][1]]),key[u])); } struct Edge{ int to,next; }edge[maxn*2]; int head[maxn],tot; void addedge(int u,int v){ edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++; } void dfs(int u){ for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].to; if(pre[v]!=0) continue; pre[v]=u; dfs(v); } } int main() { int n,q,u,v; while(scanf("%d",&n)!=EOF){ tot=0; for(int i=0;i<=n;i++){ head[i]=-1; pre[i]=0; ch[i][0]=ch[i][1]=0; rev[i]=0; add[i]=0; rt[i]=true; } Max[0]=-0x3f3f3f3f; for(int i=1;i<n;i++){ scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } for(int i=1;i<=n;i++){ scanf("%d",&key[i]); Max[i]=key[i]; } scanf("%d",&q); pre[1]=-1; dfs(1); //处理出pre pre[1]=0; int op; while(q--){ scanf("%d",&op); if(op==1){ int x,y; scanf("%d%d",&x,&y); link(x,y); } else if(op==2){ int x,y; scanf("%d%d",&x,&y); cut(x,y); } else if(op==3){ int w,x,y; scanf("%d%d%d",&w,&x,&y); ADD(x,y,w); } else{ int x,y; scanf("%d%d",&x,&y); query(x,y); } } printf("\n"); } return 0; }
hdu 4010 Query on The Trees(动态树)
标签:
原文地址:http://www.cnblogs.com/dominatingdashuzhilin/p/4740985.html