「hdu4010」Query on The Trees【LCT】

Query on The Trees

Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Others)
Total Submission(s): 7636 Accepted Submission(s): 2913

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 NN nodes, each node will have a unique weight WiW_i. 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.(1N300000)N.(1 \leq N \leq 300000) The next N1N‐1 lines each contains two integers x,yx, y which means there is an edge between them. It also means we will give you one tree initially.
The next line will contains NN integers which means the weight WiW_i of each node. (0Wi3000)(0 \leq W_i \leq 3000)
The next line will contains an integer Q.(1Q300000)Q. (1 \leq Q \leq 300000) The next QQ lines will start with an integer 1,2,31, 2, 3 or 44 means the kind of this operation.

  1. Given two integer x,y,x, y, you should make a new edge between these two node xx and yy. So after this operation, two trees will be connected to a new one.
  2. Given two integer x,y,x, y, you should find the tree in the tree set who contain node xx, and you should make the node xx be the root of this tree, and then you should cut the edge between node yy and its parent. So after this operation, a tree will be separate into two parts.
  3. Given three integer w,x,y,w, x, y, for the x,yx, y and all nodes between the path from xx to yy, you should increase their weight by w.w.
  4. Given two integer x,y,x, y, you should check the node weights on the path between xx and yy, 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‐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 xx and yy belong to a same tree, we think it’s illegal.
In second operation: if x=yx = y or xx and yy not belong to a same tree, we think it’s illegal.
In third operation: if xx and yy not belong to a same tree, we think it’s illegal.
In fourth operation: if xx and yy not belong to a same tree, we think it’s illegal.

Source

The 36th ACM/ICPC Asia Regional Dalian Site —— Online Contest

题意

  • 开始给你一颗带点权的树,然后实现一下操作
  1. 连接x yx\ y
  2. xx成为树根,然后分离出以yy为根的子树
  3. xxyy的路径上的所有节点的权值加上ww
  4. 查询从xxyy的简单路径上的最大点权

题解

  • 虽然是一个比较简单的LCTLCT,但是还是有很多需要注意的地方
  • 自己实现一些LCTLCT的函数时,要注意是否需要下放标记,上传标记,比如上述第22个操作,稍不注意可能就会wawa
  • 对于LCTLCT实现的一些简单路径所有节点修改操作,可以将标记放在区间翻转操作一起,同步下放标记,所以LCTLCT很好维护 ,只用修改push_downpush\_down函数就行了
  • 本题一个小坑就是多组数据,然后修改操作如果不合法也需要输出1-1

代码

#include<bits/stdc++.h>

using namespace std;
const int maxn=3e5+10;
#define inf 0x3f3f3f3f

namespace IO{ 
    #define BUF_SIZE 100000 
    #define OUT_SIZE 100000 

    bool IOerror=0; 
    inline char nc(){ 
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE; 
        if(p1==pend){ 
            p1=buf;pend=buf+fread(buf,1,BUF_SIZE,stdin); 
            if(pend==p1){IOerror=1;return -1;} 
        } 
        return *p1++; 
    } 
    inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';} 
    inline bool read(double &x){ 
        bool sign=0; char ch=nc(); x=0; 
        for(;blank(ch);ch=nc()); 
        if(IOerror) return false; 
        if(ch=='-')sign=1,ch=nc(); 
        for(;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0'; 
        if(ch=='.'){ 
            double tmp=1;ch=nc(); 
            for(;ch>='0'&&ch<='9';ch=nc())tmp/=10.0,x+=tmp*(ch-'0'); 
        } 
        if(sign)x=-x;return true;
    }
    template<typename T>
    inline bool read(T &x){ 
        bool sign=0; char ch=nc(); x=0; 
        for(;blank(ch);ch=nc()); 
        if(IOerror) return false; 
        if(ch=='-')sign=1,ch=nc(); 
        for(;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0'; 
        if(sign)x=-x; return true;
    } 
    inline bool read(char *s){ 
        char ch=nc(); 
        for(;blank(ch);ch=nc()); 
        if(IOerror) return false; 
        for(;!blank(ch)&&!IOerror;ch=nc())*s++=ch; 
        *s=0;return true;
    } 
};
using namespace IO;


namespace LCT{
    int ch[maxn][2],fa[maxn],mark[maxn];
    long long val[maxn],ans[maxn],lazy[maxn];
    inline bool not_root(int x) {return ch[fa[x]][0]==x||ch[fa[x]][1]==x;}
    inline int dir(int x) {return ch[fa[x]][1]==x;}
    inline void add_mark(int x) {swap(ch[x][0],ch[x][1]);mark[x]^=1;}        //将x这颗子树翻转
    inline void push_down(int x) {
        if(mark[x]) {
            if(ch[x][0]) add_mark(ch[x][0]);
            if(ch[x][1]) add_mark(ch[x][1]); 
            mark[x]=0;
        }
        if(lazy[x]) {
            if(ch[x][0]) {
                lazy[ch[x][0]]+=lazy[x];
                val[ch[x][0]]+=lazy[x];
                ans[ch[x][0]]+=lazy[x];
            }
            if(ch[x][1]) {
                lazy[ch[x][1]]+=lazy[x];
                val[ch[x][1]]+=lazy[x];
                ans[ch[x][1]]+=lazy[x];
            }
            lazy[x]=0;
        }
    }

    inline void push_up(int x) {
        ans[x]=val[x];
        if(ch[x][0]) ans[x]=max(ans[x],ans[ch[x][0]]);
        if(ch[x][1]) ans[x]=max(ans[x],ans[ch[x][1]]);
        
    }
    inline void pushall(int x) {
        if(not_root(x)) pushall(fa[x]);
        push_down(x);
    }
    inline void rotate(int x){
        int y=fa[x],z=fa[y],k=dir(x);
        if(ch[x][k^1]) fa[ch[x][k^1]]=y;ch[y][k]=ch[x][k^1];
        if(not_root(y)) ch[z][dir(y)]=x;fa[x]=z;
        ch[x][k^1]=y;fa[y]=x;
        push_up(y);push_up(x);
    }
    inline void splay(int x,int goal=0) {
        pushall(x);
        while(not_root(x)) {
            int y=fa[x],z=fa[y];
            if(not_root(y)) {
                if(dir(x)==dir(y)) rotate(y);
                else rotate(x);
            }
            rotate(x);
        }
        //push_up(x);
    }
    inline void access(int x) {    //从原树的根向x拉一条实链
        for(int y=0;x;y=x,x=fa[x]) {
            splay(x);ch[x][1]=y;push_up(x);
        }
    }
    inline void make_root(int x) {  //使x成为splay的根
        access(x);splay(x);add_mark(x);
    }
    inline int find_root(int x) {   //找到x在原树中的根
        access(x);splay(x);
        while(ch[x][0]) push_down(x),x=ch[x][0];
        splay(x);
        return x;
    }
    inline void split(int x,int y) {   //拉出一条x->y的实链,y为splay根
        make_root(x);access(y);splay(y);
    }
    inline bool link(int x,int y) {    //连接x与y,若已经在同一颗原树中,返回0
        make_root(x);
        fa[x]=y;return 1;
    } 
    inline bool cut(int x,int y) {
        make_root(x);
        if(find_root(y)!=x||fa[y]!=x||ch[y][0]) return 0;
        fa[y]=ch[x][1]=0;
        push_up(x);
        return 1;
    }
    inline long long query_max(int l,int r) {
        split(l,r);
        return ans[r];
    }

};
using namespace LCT;

int n,m,opt,u[maxn],v[maxn];
int main()
{
    while(read(n)) {
        for(int i=1;i<n;i++) read(u[i]),read(v[i]);
        for(int i=1;i<=n;i++) read(val[i]);
        for(int i=1;i<n;i++) link(u[i],v[i]);
        read(m);
        for(int i=1,u,v,w;i<=m;i++) {
            read(opt),read(u),read(v);
            if(opt==1) {
                if(find_root(u)==find_root(v)) printf("-1\n");
                else link(u,v);
            }
            else if(opt==2) {
                if(u==v||find_root(u)!=find_root(v)) {
                    printf("-1\n");
                    continue;
                }
                split(u,v);
                push_down(v);push_down(ch[v][0]);
                int f=ch[v][0];
                while(ch[f][1]) {f=ch[f][1];push_down(f);}
                cut(v,f);
            }else if(opt==3) {
                read(w);
                if(find_root(v)!=find_root(w)) {
                    printf("-1\n");
                    continue;
                }
                split(v,w);
                ans[w]+=u;
                lazy[w]+=u;
                val[w]+=u;
            }else {
                if(find_root(u)!=find_root(v)) printf("-1\n");
                else printf("%lld\n",query_max(u,v));
            }
        }
        for(int i=1;i<=n;i++) val[i]=mark[i]=lazy[i]=ans[i]=ch[i][0]=ch[i][1]=fa[i]=0;
        printf("\n");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章