hdu 4010 Query on The Trees

Query on The Trees

http://acm.hdu.edu.cn/showproblem.php?pid=4010

                                           Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)

Problem Description
We have met so many problems on the tree, so today we will have a query problem on a set of trees.
There are N nodes, each node will have a unique weight Wi. We will have four kinds of operations on it and you should solve them efficiently. Wish you have fun!
 
Input
There are multiple test cases in our dataset.
For each case, the first line contains only one integer N.(1 ≤ N ≤ 300000) The next N‐1 lines each contains two integers x, y which means there is an edge between them. It also means we will give you one tree initially.
The next line will contains N integers which means the weight Wi of each node. (0 ≤ Wi ≤ 3000)
The next line will contains an integer Q. (1 ≤ Q ≤ 300000) The next Q lines will start with an integer 1, 2, 3 or 4 means the kind of this operation.
1. Given two integer x, y, you should make a new edge between these two node x and y. So after this operation, two trees will be connected to a new one.
2. Given two integer x, y, you should find the tree in the tree set who contain node x, and you should make the node x be the root of this tree, and then you should cut the edge between node y and its parent. So after this operation, a tree will be separate into two parts.
3. Given three integer w, x, y, for the x, y and all nodes between the path from x to y, you should increase their weight by w.
4. Given two integer x, y, you should check the node weights on the path between x and y, and you should output the maximum weight on it.
 
Output
For each query you should output the correct answer of it. If you find this query is an illegal operation, you should output ‐1.
You should output a blank line after each test case.
 
Sample Input
5 1 2 2 4 2 5 1 3 1 2 3 4 5 6 4 2 3 2 1 2 4 2 3 1 3 5 3 2 1 4 4 1 4
 
Sample Output
3 -1 7
Hint
We define the illegal situation of different operations:
In first operation: if node x and y belong to a same tree, we think it's illegal.
In second operation: if x = y or x and y not belong to a same tree, we think it's illegal.
In third operation: if x and y not belong to a same tree, we think it's illegal.
In fourth operation: if x and y not belong to a same tree, we think it's illegal.
 
Source
题目大意:
写一种数据结构,支持以下操作:
1、如果x和y不在同一棵树中,在x和y之间连一条边
2、如果x和y在同一棵树中,同时x!=y,断掉x和y之间的边
3、如果x和y在同一棵树中,从x到y的路径上所有的点都+w
4、如果x和y在同一棵树中,输出从x到y路径上所有点的最大值
如果不满足“如果”条件,输出-1
 
直接上LCT
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 300005
using namespace std;
int n,fa[N],st[N],ch[N][2],maxn[N],tag[N],rev[N],key[N],top;
int last[N],cnt,q[N];
struct edge{int to,next;}e[N<<1];
void insert(int u,int v)
{
    e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;
    e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;
}
inline void up(int x)
{
    maxn[x]=max(maxn[ch[x][1]],maxn[ch[x][0]]);
    maxn[x]=max(maxn[x],key[x]);
}
inline void down(int x)
{
    if(rev[x]) 
    {
        rev[x]^=1;rev[ch[x][1]]^=1;rev[ch[x][0]]^=1;
        swap(ch[x][0],ch[x][1]);
    }
    if(tag[x])
    {
        if(ch[x][0]) maxn[ch[x][0]]+=tag[x],tag[ch[x][0]]+=tag[x],key[ch[x][0]]+=tag[x];
        if(ch[x][1]) maxn[ch[x][1]]+=tag[x],tag[ch[x][1]]+=tag[x],key[ch[x][1]]+=tag[x];
        tag[x]=0;
    } 
}
inline bool isroot(int x)
{
    return ch[fa[x]][1]!=x&&ch[fa[x]][0]!=x;
}
inline void rotate(int x)
{
    int y=fa[x],z=fa[y],l,r;
    if(ch[y][0]==x) l=0; else l=1;
    r=l^1;
    if(!isroot(y))
    {
        if(ch[z][0]==y) ch[z][0]=x;
        else ch[z][1]=x;
    } 
    ch[y][l]=ch[x][r];ch[x][r]=y;
    fa[x]=z;fa[y]=x;fa[ch[y][l]]=y;
    up(y);
}
inline void splay(int x)
{
    int t=0;st[++t]=x;
    for(int i=x;!isroot(i);i=fa[i]) st[++t]=fa[i];
    for(int i=t;i;i--) down(st[i]);
    while(!isroot(x))
    {
        int y=fa[x],z=fa[y];
        if(!isroot(y))
        {
            if(ch[y][0]==x^ch[z][0]==y) rotate(x);
            else rotate(y);
        }
        rotate(x);
        up(x);
    }
}
inline void access(int x)
{
    int t=0;
    while(x)
    {
        splay(x);
        ch[x][1]=t;
        up(x);
        t=x;x=fa[x];
    } 
}
inline int findroot(int x)
{
    access(x);
    splay(x);
    while(ch[x][0]) x=ch[x][0];
    return x;
}
inline void make_root(int x)
{
    access(x);
    splay(x);
    rev[x]^=1;
}
inline void link(int x,int y)
{
    make_root(x);
    fa[x]=y;
}
inline void cut(int x,int y)
{
    make_root(x);
    access(y);
    splay(y);
    ch[y][0]=fa[ch[y][0]]=0;
    up(y);
}
inline bool judge(int x,int y)
{
    int a=findroot(x);
    int b=findroot(y);
    if(a==b) return true;
    return false;
}
inline void pre()
{
    memset(fa,0,sizeof(fa));
    memset(ch,0,sizeof(ch));
    memset(maxn,0,sizeof(maxn));
    memset(tag,0,sizeof(tag));
    memset(rev,0,sizeof(rev));
    memset(last,0,sizeof(last));
    top=0;
    maxn[0]=-200000000;
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        int x,y,p,z;
        pre();
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y); 
            insert(x,y);
        }
        for(int i=1;i<=n;i++) 
        {
            scanf("%d",&key[i]);
            maxn[i]=key[i];
        }
        q[++top]=1;
        for(int k=1;k<=top;k++)
        {
            int now=q[k];
            for(int i=last[now];i;i=e[i].next)
                if(e[i].to!=fa[now])
                {
                    fa[e[i].to]=now;
                    q[++top]=e[i].to;
                }
        }
        int m;
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&p);
            if(p==1)
            {
                scanf("%d%d",&x,&y);
                if(!judge(x,y))  link(x,y);
                else printf("-1
");
            }
            else if(p==2)
            {
                scanf("%d%d",&x,&y);
                if(x!=y&&judge(x,y))  cut(x,y);
                else printf("-1
");
            }
            else if(p==3)
            {
                scanf("%d%d%d",&x,&y,&z);
                if(judge(y,z))
                {
                    make_root(y);
                    access(z);
                    splay(z);
                    maxn[z]+=x;
                    tag[z]+=x;
                    key[z]+=x;
                }
                else printf("-1
");
            }
            else
            {
                scanf("%d%d",&x,&y);
                if(judge(x,y))
                {
                    make_root(x);
                    access(y);
                    splay(y);
                    printf("%d
",maxn[y]);
                }
                else printf("-1
");
            } 
        }
        printf("
");
    }
}

3个错误:

1、开始建树方法错误

错误代码:

for(int i=1;i<n;i++)
{
  scanf("%d%d",&x,&y);
  if(x<y) swap(x,y);
  fa[x]=y;
}

应该用遍历的方法建树

这个样不能保证只有一个根节点

2、更新答案错误

inline void up(int x)
{
     maxn[x]=max(maxn[ch[x][1]],maxn[ch[x][0]]);
     maxn[x]=max(maxn[x],key[x]);
}

漏了第2句,这也是key数组的作用

3、多组数据,top没有清0

原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/6477230.html