HDU 4010 Query on The Trees(动态树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4010

题意:一棵树,四种操作:

(1)若x和y不在一棵树上,将x和y连边;

(2)若x和y在一棵树上,将x变成树根,将y从x树上分离;

(3)若x和y在一棵树上,将x到y路径上的所有值增加det;

(4)若x和y在一棵树上,输出x到y路径上的最大值。

思路:一、由于出现的多棵树,那么每次操作之前都要判断询问的两个节点是不是在一棵树上,比如对于操作(2)(3)(4)来说都要保证x和y在一棵树上时操作才是合法的;对于(1)则x和y不能在一棵树上。首先,我们用一个函数makeroot(x)表示将x设为x所在树(是树而不是树链)的根。其实就是将x到其所在树的树根的路径上的边全部反向,那么x就会成为根。我们先access(x),那么x就与root连在一起,然后splay(x),x就调整到了根的位置,但是还不是跟,因为root现在其实在x的左孩子或者左孩子的子孙,x的右孩子现在为null,因为我们access(x)的时候将x与其右孩子断开了;那么现在我们将x的左孩子和右孩子互换(其实就是将右孩子设为左孩子,左孩子设为null),那么此时x就成为了真正的树根;

二、有了makeroot(x)之后,我们怎么判断x和y是不是在一个树上呢?首先makeroot(x),x成为树根;x的父节点为null。接着access(y),splay(y),试想,若x和y不在一棵树上,那么此时y的操作与x无任何关系,此时x的父节点还是null;但是,y若与x在一棵树上就不同了,现在y成了树根(只是调整到了树根的位置,x才是真正的树根),那么x必然是y的左孩子或者左孩子的子孙,即x的父节点不为空。据此,我们根据x的父节点是不是为null可判断x和y是否在一棵树上;其实用makeroot(y)代替access(y),splay(y)也是可以的,不好的地方就是这样就改变了树的真实结构;

三、现在我们说说对于题目中的四个操作怎么做:

(1)makeroot(x),access(y),splay(y),x和y若不在一棵树上,此时x的父节点为null,因此直接将x的父节点设为y;

(2)makeroot(x),access(y),splay(y),x和y若在一棵树上,y的右孩子实际是y的子孙,加上y也就是y所在子树,y的左孩子是y的祖宗节点,因此将y的左孩子置为null,同时将y左孩子的父节点置为null。

(3)(4)差不多,增加标志就可以。

 

struct node

{

    int det,val,Max,isReversed;

    node *c[2],*f;



    void add(int x)

    {

        val+=x;

        det+=x;

        Max+=x;

    }



    void reverse()

    {

        isReversed^=1;

        swap(c[0],c[1]);

    }

};



node a[N],*nullNode;

int n;



void pushUp(node *p)

{

    p->Max=max(p->val,max(p->c[0]->Max,p->c[1]->Max));

}







void pushDown(node *p)

{

    if(p->det)

    {

        if(p->c[0]!=nullNode) p->c[0]->add(p->det);

        if(p->c[1]!=nullNode) p->c[1]->add(p->det);

        p->det=0;

    }

    if(p->isReversed)

    {

        if(p->c[0]!=nullNode) p->c[0]->reverse();

        if(p->c[1]!=nullNode) p->c[1]->reverse();

        p->isReversed=0;

    }

}



void rotate(node *p,int k)

{

    node *q=p->f;

    q->c[k]=p->c[!k];

    if(p->c[!k]!=nullNode) p->c[!k]->f=q;

    p->c[!k]=q;

    p->f=q->f;

    if(q->f!=nullNode)

    {

        if(p->f->c[0]==q) p->f->c[0]=p;

        if(p->f->c[1]==q) p->f->c[1]=p;

    }

    q->f=p;

    pushUp(q);

}



int isRoot(node *p)

{

    return p->f==nullNode||p->f->c[0]!=p&&p->f->c[1]!=p;

}





void splay(node *p)

 {

     pushDown(p);

     while (!isRoot(p))

     {

         if(isRoot(p->f))

         {

             pushDown(p->f);

             pushDown(p);

             if(p==p->f->c[0]) rotate(p,0);

             else rotate(p,1);

         }

         else

         {

             pushDown(p->f->f);

             pushDown(p->f);

             pushDown(p);

             if(p->f->f->c[0]==p->f)

             {

                 if(p->f->c[0]==p) rotate(p->f,0);

                 else rotate(p,1);

                 rotate(p,0);

             }

             else

             {

                 if(p->f->c[1]==p) rotate(p->f,1);

                 else rotate(p,0);

                 rotate(p,1);

             }

         }

     }

     pushUp(p);

}



node* access(node *p)

{

    node *q=nullNode;

    while(p!=nullNode)

    {

        splay(p);

        p->c[1]=q;

        pushUp(p);

        q=p;

        p=p->f;

    }

    return q;

}







void makeRoot(int x)

{

    access(a+x);

    splay(a+x);

    a[x].reverse();

}



void join(int x,int y)

{

    if(x==y)

    {

        puts("-1");

        return;

    }

    makeRoot(x);access(a+y);splay(a+y);

    if(a[x].f==nullNode) a[x].f=a+y;

    else puts("-1");

}



void cut(int x,int y)

{

    makeRoot(x);access(a+y);splay(a+y);

    if(a[x].f==nullNode) puts("-1");

    else

    {

        a[y].c[0]->f=nullNode;

        a[y].c[0]=nullNode;

        pushUp(a+y);

    }

}



void change(int x,int y,int val)

{

    makeRoot(y);access(a+x);splay(a+x);

    if(a[y].f==nullNode)

    {

        puts("-1");

        return;

    }



    access(a+x);

    node *lca=access(a+y);

    if(lca->c[1]!=nullNode) lca->c[1]->add(val);

    lca->val+=val;

    if(a+x!=lca&&(a+x)!=nullNode) splay(a+x),a[x].add(val);

    pushUp(lca);

}



int query(int x,int y)

{

    if(x==y) return a[x].val;

    makeRoot(y);access(a+x);splay(a+x);

    if(a[y].f==nullNode) return -1;



    access(a+x);

    node *lca=access(a+y);

    int ans;

    if(a+x!=nullNode) splay(a+x);

    if(a+x!=lca)

    {

        ans=max(lca->c[1]->Max,a[x].Max);

        ans=max(ans,lca->val);

    }

    else

    {

        ans=max(lca->c[1]->Max,lca->val);

    }

    return ans;

}



struct Node

{

    int v,next;

};



Node edges[N];

int head[N],e;





void Add(int u,int v)

{

    edges[e].v=v;

    edges[e].next=head[u];

    head[u]=e++;



    edges[e].v=u;

    edges[e].next=head[v];

    head[v]=e++;

}



void build()

{

    queue<int> Q;

    Q.push(1);

    int i,u,v;

    while(!Q.empty())

    {

        u=Q.front();

        Q.pop();



        for(i=head[u];i!=-1;i=edges[i].next)

        {

            v=edges[i].v;

            if(a+v==a[u].f) continue;

            a[v].f=a+u;

            Q.push(v);

        }

    }



}



int get()

{

    int x=0,flag=1;

    char c=getchar();

    while(!isdigit(c)) c=getchar();

    if(c=='-')

    {

        flag=-1,c=getchar();

        while(!isdigit(c)) c=getchar();

    }

    while(isdigit(c))

    {

        x=x*10+c-'0';

        c=getchar();

    }

    return x*flag;

}







void init()

{

    nullNode=new node();

    nullNode->isReversed=0;

    nullNode->det=0;

    nullNode->Max=-INF;

    nullNode->val=-INF;

    nullNode->c[0]=nullNode->c[1]=nullNode->f=nullNode;

    int i,u,v,dis;

    clr(head,-1);

    e=0;

    FOR1(i,n-1) u=get(),v=get(),Add(u,v);

    FOR1(i,n)

    {

        dis=get();

        a[i].c[0]=a[i].c[1]=a[i].f=nullNode;

        a[i].isReversed=0;

        a[i].det=0;

        a[i].Max=a[i].val=dis;

    }

    build();

}



int main()

{

    while(scanf("%d",&n)!=-1)

    {

        init();

        int a,b,c,op,m=get();

        while(m--)

        {

            op=get();

            if(op==1) a=get(),b=get(),join(a,b);

            else if(op==2) a=get(),b=get(),cut(a,b);

            else if(op==3) c=get(),a=get(),b=get(),change(a,b,c);

            else a=get(),b=get(),PR(query(a,b));

        }

        puts("");

    }

    return 0;

}

 

你可能感兴趣的:(query)