zoukankan      html  css  js  c++  java
  • 【题解】 QTREE6 LCT维护子树信息 SPOJ16549

    Legend

    Link ( extrm{to SPOJ})

    一棵树,每个点初始为白色。

    • 0 u :询问满足 (u o v) 的路径上的点颜色全部相同的 (v) 的数量。

    • 1 u :反转 (u) 的颜色(异或 1)。

    结点个数与操作小于 (10^5)

    Editorial

    容易想到一个做法是对于每一个点维护以它为 ( m{LCA}) 的极大同色连通块的大小。

    修改时候一定是修改一个从当前结点到根的一个连续段,减去相同的数。

    不管感觉好像不太好写,于是就看了看题解,发现是个 ( m{LCT})

    因为单次修改会带动一堆相邻的点,很烦。所以考虑把点颜色放到它到它直接祖先的这条边上。

    对于根,搞一个虚拟结点当祖先。

    维护两棵线段树,一棵只连白色边,一棵只连黑色边。

    查询的时候找到当前连通块的 ( m{LCA})(注意到 ( m{LCA}) 一定是与询问结点的颜色不同的)。

    也就是直接 findroot 一下,把这个 ( m{LCA}) 转到 splay 的根。

    接着查询这个 ( m{LCA}) 实儿子大小(也就是刚刚 access 上来的那个连通块的大小)就是答案。

    Code

    有一定细节,十分考验对 ( m{LCT}) 的理解程度。

    最主要的是,做任何修改前一定要把它转到根,这样可以有效避免错误。

    #include <bits/stdc++.h>
    
    #define debug(...) ;//+fprintf(stderr ,__VA_ARGS__)
    #define __FILE(x)
    	freopen(#x".in" ,"r" ,stdin);
    	freopen(#x".out" ,"w" ,stdout)
    #define LL long long
    
    using namespace std;
    
    const int MX = 1e5 + 23;
    
    int read(){
    	char k = getchar(); int x = 0;
    	while(k < '0' || k > '9') k = getchar();
    	while(k >= '0' && k <= '9') x = x * 10 + k - '0' ,k = getchar();
    	return x;
    }
    
    int n;
    struct LCT{
    #define lch(x) ch[x][0]
    #define rch(x) ch[x][1]
    	int ch[MX][2] ,fa[MX] ,size[MX] ,Vsize[MX];
    	LCT(){for(int i = 1 ; i < MX ; ++i) size[i] = 1;}
    	int get(int x){return x == rch(fa[x]);}
    	int Nroot(int x){return get(x) || x == lch(fa[x]);}
    	void pushup(int x){size[x] = size[lch(x)] + size[rch(x)] + Vsize[x] + 1;}
    	void rotate(int x){
    		int f = fa[x] ,gf = fa[f] ,which = get(x) ,W = ch[x][!which];
    		if(Nroot(f)) ch[gf][get(f)] = x;
    		ch[x][!which] = f ,ch[f][which] = W;
    		if(W) fa[W] = f;
    		fa[f] = x ,fa[x] = gf ,pushup(f);
    	}
    	void splay(int x){
    		int f;
    		while(Nroot(x)){
    			if(Nroot(f = fa[x])) rotate(get(x) == get(f) ? f : x);
    			rotate(x);
    		}pushup(x);
    	}
    	void access(int x){
    		for(int y = 0 ; x ; x = fa[y = x]){
    			splay(x);
    			Vsize[x] += size[rch(x)];
    			Vsize[x] -= size[rch(x) = y];
    			pushup(x);
    		}
    	}
    	int findroot(int x){
    		access(x);
    		splay(x);
    		while(lch(x)) x = lch(x);
    		splay(x);
    		return x;	
    	}
    	void link(int x ,int y){
    		splay(x);
    		access(y); splay(y);
    		fa[x] = y;
    		Vsize[y] += size[x];
    		pushup(y);	
    	}
    	void cut(int x ,int y){
    
    		access(x);
    		splay(y);
    		rch(y) = fa[x] = 0;
    		pushup(y);
    	}
    	void output(){
    		debug("Tree info:
    ");
    		for(int i = 1 ; i <= n + 1 ; ++i){
    			debug("[%d] fa: %d ch:{%d ,%d} sz: %d vsz %d
    " ,i ,fa[i] ,ch[i][0] ,ch[i][1] ,size[i] ,Vsize[i]);
    		}
    	}
    #undef lch
    #undef rch
    }T[2];
    
    int head[MX] ,tot = 1;
    struct edge{
    	int node ,next;
    }h[MX << 1];
    void addedge(int u ,int v ,int flg = 1){
    	h[++tot] = (edge){v ,head[u]} ,head[u] = tot;
    	if(flg) addedge(v ,u ,false);
    }
    
    int fa[MX] ,c[MX];
    void dfs(int x){
    	T[c[x]].link(x ,fa[x]);
    	debug("FA[%d] = %d
    " ,x ,fa[x]);
    	for(int i = head[x] ,d ; i ; i = h[i].next){
    		if((d = h[i].node) == fa[x]) continue;
    		debug("%d->%d
    " ,x ,d);
    		fa[d] = x ,dfs(d);
    	}
    }
    
    void solve(){
    	n = read();
    	
    	for(int i = 1 ,u ,v ; i < n ; ++i){
    		u = read() ,v = read();
    		addedge(u ,v);
    	}
    	fa[1] = n + 1;
    	dfs(1);
    	// T[0].makeroot(n + 1);
    	// T[0].output();
    	int Q = read();
    	while(Q--){
    		int type = read() ,x = read();
    		if(type == 0){
    			int rt = T[c[x]].findroot(x);
    			debug("RT = %d
    " ,rt);
    			printf("%d
    " ,T[c[x]].size[rt] - T[c[x]].Vsize[rt] - 1);
    		}
    		else{
    			T[c[x]].cut(x ,fa[x]);
    			c[x] ^= 1;
    			T[c[x]].link(x ,fa[x]);
    		}
    		// T[0].output();
    		// T[1].output();
    	}
    }
    
    int main(){
    	int T = 1;
    	for(int i = 1 ; i <= T ; ++i){
    		solve();
    	}
    	return 0;
    }
    
  • 相关阅读:
    [通信] C# TCP实现多个客户端与服务端 数据 与 文件的传输
    [压缩]C#下使用SevenZipSharp压缩解压文本
    [通信] C#多线程Socket-文件传输
    [算法] N 皇后
    【算法】N Queens Problem
    [Eclipse]
    [C/C++] String Reverse 字符串 反转
    [SQL] 获取 Microsoft SQL Server 2008 的数据表结构
    [WIFI] WIFI 破解(初级)
    Unable to extract 64-bitimage. Run Process Explorer from a writeable directory
  • 原文地址:https://www.cnblogs.com/imakf/p/13903998.html
Copyright © 2011-2022 走看看