「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 N N N nodes, each node will have a unique weight W i W_i 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 ) N.(1 \leq N \leq 300000) N.(1N300000) The next N ‐ 1 N‐1 N1 lines each contains two integers x , y x, y 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 N N integers which means the weight W i W_i Wi of each node. ( 0 ≤ W i ≤ 3000 ) (0 \leq W_i \leq 3000) (0Wi3000)
The next line will contains an integer Q . ( 1 ≤ Q ≤ 300000 ) Q. (1 \leq Q \leq 300000) Q.(1Q300000) The next Q Q Q lines will start with an integer 1 , 2 , 3 1, 2, 3 1,2,3 or 4 4 4 means the kind of this operation.

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

Source

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

题意

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

题解

  • 虽然是一个比较简单的 L C T LCT LCT,但是还是有很多需要注意的地方
  • 自己实现一些 L C T LCT LCT的函数时,要注意是否需要下放标记,上传标记,比如上述第 2 2 2个操作,稍不注意可能就会 w a wa wa
  • 对于 L C T LCT LCT实现的一些简单路径所有节点修改操作,可以将标记放在区间翻转操作一起,同步下放标记,所以 L C T LCT LCT很好维护 ,只用修改 p u s h _ d o w n push\_down push_down函数就行了
  • 本题一个小坑就是多组数据,然后修改操作如果不合法也需要输出 − 1 -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");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值