[Libre][SDOI2017]樹點塗色
阿新 • • 發佈:2018-04-05
hang tin += http != 表示 塗色 include 進行
鏈接
(蒟蒻只能夠想到 3 操作可以用樹剖線段樹維護ORZ)
對於每個 1 操作 , 都會覆蓋當前節點到根節點的所有顏色 , 且新顏色對所有經過操作節點的路徑都有貢獻。
所以我們維護所有邊的兩邊顏色是否相同 , 易知在不相同情況下這條邊有1的貢獻 , 在這種情況下我們就能夠對 2 操作進行維護了(考慮差分)
在這裏我們用 $ D_{i} $ 表示點 i 到根存在多少這樣的邊 ,則操作 2 的 答案為 $ Ans = D_{x} + D_{y} - 2 * D_{lca(x , y)} + 1 $
接下來考慮如何維護這些邊。
我們會發現覆蓋當前節點到根節點的操作與 LCT 中的 Access 操作類似 ,
所以在這裏我們就可以用輕重邊來表示這些不同的邊了!
用 Access 來模擬操作 1 過程 , 重邊 - > 輕邊 則進行子樹加 , 輕邊 - > 重邊 則進行子樹減
由於我們只要維護 LCT 中的 Access , 所以只要對Access操作進行一些修改就行了
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cmath> using namespace std; const int N = 1e5 + 5; struct Virt{ double x , y; Virt(double _x = 0.0 , double _y = 0.0):x(_x) , y(_y){} }; Virt operator + (Virt x , Virt y){return Virt(x.x + y.x , x.y + y.y);} Virt operator - (Virt x , Virt y){return Virt(x.x - y.x , x.y - y.y);} Virt operator * (Virt x , Virt y){return Virt(x.x * y.x - x.y * y.y , x.x * y.y + x.y * y.x);} int read(){ int x = 0 , f = 1; char ch = getchar(); while(ch < ‘0‘ || ch > ‘9‘){if(ch == ‘-‘) f = -1 ; ch = getchar();} while(ch >= ‘0‘ && ch <= ‘9‘){x = x * 10 + ch - ‘0‘; ch = getchar();} return x * f; } int n , Q , opt , x , y; int num , posin[N] , posout[N] , tot , head[N]; int fa[N] , dep[N] , sz[N] , top[N] , son[N] , tree[N]; struct edge{ int pos , nx; }e[N << 1]; void add(int u , int v){ e[++num].pos = v; e[num].nx = head[u]; head[u] = num; e[++num].pos = u; e[num].nx = head[v]; head[v] = num; } void dfs1(int now){ sz[now] = 1; for(int i = head[now] ; i ; i = e[i].nx){ if(e[i].pos == fa[now]) continue; fa[e[i].pos] = now; dep[e[i].pos] = dep[now] + 1; dfs1(e[i].pos); sz[now] += sz[e[i].pos]; if(sz[e[i].pos] > sz[son[now]]) son[now] = e[i].pos; } } void dfs2(int now , int father){ posin[now] = ++tot; tree[tot] = now; top[now] = father; if(son[now]) dfs2(son[now] , father); for(int i = head[now] ; i ; i = e[i].nx){ if(e[i].pos == son[now] || e[i].pos == fa[now]) continue; dfs2(e[i].pos , e[i].pos); } posout[now] = tot; } int lca(int x , int y){ while(top[x] != top[y]){ if(dep[top[x]] < dep[top[y]]) swap(x,y); x = fa[top[x]]; } return dep[x] < dep[y] ? x : y; } struct SegmentTree{ struct node{ int tag , val; }tr[N << 2]; void paint(int k , int d){ tr[k].tag += d; tr[k].val+=d; } void push_down(int k){ paint(k << 1 , tr[k].tag); paint(k << 1 | 1 , tr[k].tag); tr[k].tag = 0; } void merge(int k){tr[k].val = max(tr[k << 1].val , tr[k << 1 | 1].val);} void build(int k , int l , int r){ if(l == r) tr[k].val = dep[tree[l]] + 1; else build(k << 1 , l , (l + r) >> 1) , build(k << 1 | 1 , ((l + r) >> 1) + 1 , r) , merge(k); } int query1(int k , int l , int r , int pos){ if(l == r) return tr[k].val; else{ if(tr[k].tag) push_down(k); int mid = (l + r) >> 1; if(mid >= pos) return query1(k << 1 , l , mid , pos); else return query1(k << 1 | 1, mid + 1 , r , pos); } } int query2(int k , int l , int r , int L , int R){ if(L <= l && r <= R) return tr[k].val; else{ if(tr[k].tag) push_down(k); int mid = (l + r) >> 1 , ans = 0; if(mid >= L) ans = max(ans , query2(k << 1 , l , mid , L , R)); if(mid < R) ans = max(ans , query2(k << 1 | 1 , mid + 1 , r , L , R)); return ans; } } void change(int k , int l , int r , int L , int R , int d){ if(l >= L && r <= R) paint(k , d); else{ if(tr[k].tag) push_down(k); int mid = (l + r) >> 1; if(mid >= L) change(k << 1 , l , mid , L , R , d); if(mid < R) change(k << 1 | 1 , mid + 1 , r , L , R , d); merge(k); } } }seg; void addsub(int k , int d){seg.change(1 , 1 , n , posin[k] , posout[k] , d);} int subquery(int x , int y){ int temp = lca(x , y); //printf("lca : %d\n",temp); int ans = seg.query1(1 , 1 , n , posin[x]) + seg.query1(1 , 1 , n , posin[y]) - 2 * seg.query1(1 , 1 , n , posin[temp]) + 1; return ans; } int maxquery(int k){ int ans = seg.query2(1 , 1 , n , posin[k] , posout[k]); return ans; } struct Link_Cut_Tree{ struct node{int ch[2] , fa;}tr[N]; int get_son(int x){return tr[tr[x].fa].ch[1] == x;} bool is_root(int x){return tr[tr[x].fa].ch[0] != x && tr[tr[x].fa].ch[1] != x;} void rotate(int k){ int f = tr[k].fa , ffa = tr[f].fa , c = get_son(k); if(!is_root(f)) tr[ffa].ch[tr[ffa].ch[1] == f] = k; tr[k].fa = ffa; tr[f].ch[c] = tr[k].ch[!c]; tr[tr[f].ch[c]].fa = f; tr[k].ch[!c] = f; tr[f].fa = k; } void splay(int x){ for(int f ; !is_root(x) ; rotate(x)) if(!is_root(f = tr[x].fa)) rotate(get_son(x) == get_son(f) ? f : x); } int find_root(int x){ splay(x); while(tr[x].ch[0]) x = tr[x].ch[0]; splay(x); return x; } void access(int x){ for(int y = 0 ; x ; y = x , x = tr[x].fa){ splay(x); if(tr[x].ch[1]){ int temp = tr[x].ch[1]; tr[x].ch[1] = 0; temp = find_root(temp); addsub(temp , 1); } if(y) y = find_root(y) , addsub(y , -1); tr[x].ch[1] = y; } } void init(){for(int i = 1 ; i <= n ; i++) tr[i].fa = fa[i];}; }lct; int main(){ scanf("%d%d",&n,&Q); for(int i = 1 ; i < n ; i++) scanf("%d%d",&x,&y) , add(x , y); dfs1(1); dfs2(1 , 1); seg.build(1 , 1 , n); lct.init(); for(int i = 1 ; i <= Q ; i++){ scanf("%d%d",&opt,&x); if(opt == 1) lct.access(x); else if(opt == 2) scanf("%d",&y) , printf("%d\n" , subquery(x , y)); else printf("%d\n" , maxquery(x)); } return 0; }
[Libre][SDOI2017]樹點塗色