码迷,mamicode.com
首页 > 其他好文 > 详细

hdu 4010 Query on The Trees(动态树)

时间:2015-08-19 00:26:30      阅读:104      评论:0      收藏:0      [点我收藏+]

标签:

题意:给定一幅图的连接情况,给出每个点的权值,四种操作:

        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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!