「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");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章