zoukankan      html  css  js  c++  java
  • SPOJ QTREE6

    题意

    给你一棵(n)个点的树,编号(1)~(n)。每个点可以是黑色,可以是白色。初始时所有点都是黑色。有两种操作
    (0 u):询问有多少个节点(v)满足路径(u)(v)上所有节点(包括)都拥有相同的颜色
    (1 u):翻转(u)的颜色

    Sol

    (LCT)做法:

    黑白开两个(LCT)
    然后有一个很(Naive)的做法
    就是每次改颜色时,暴力枚举连的点,(Link)(Cut)
    显然菊花树直接就卡掉了

    优化

    把树定成一棵以(1)为根的有根树,然后把颜色放在它的父亲与它相连的边上
    然后维护子树信息
    (Link)(Cut)就只涉及一条边
    注意到每个子树的根不一定同色
    询问时要特判根的颜色
    就是(Access)一下,然后(Splay),跳左儿子找到根,并把它(Splay)
    如果同色,就输出它的子树信息,否则输出它的右儿子的子树信息
    应为右儿子深度比它大,所以,右儿子的子树信息就是答案

    由于我们定义它是有根树
    那么我们不能(Makeroot),这样的话才能保证能找到当前子树的根
    那么(Link)时,为保证它父亲以上的点不受影响,(Access)(Splay)它父亲
    又因为它就是当前的子树的根,把它(Splay)一下,之后再连虚边
    (Cut)时,把它(Access)(Splay),那么它的父亲就在左子树,直接删掉它和它左儿子的实边是没有影响的

    # include <bits/stdc++.h>
    # define RG register
    # define IL inline
    # define Fill(a, b) memset(a, b, sizeof(a))
    using namespace std;
    typedef long long ll;
    const int _(1e5 + 5);
    
    IL int Input(){
    	RG int x = 0, z = 1; RG char c = getchar();
    	for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    	for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    	return x * z;
    }
    
    struct LCT{
    	typedef int Arr[_];
    	Arr fa, ch[2], sum, val;
    	
    	IL int Son(RG int x){
    		return ch[1][fa[x]] == x;
    	}
    
    	IL int Isroot(RG int x){
    		return ch[0][fa[x]] != x && ch[1][fa[x]] != x;
    	}
    	
    	IL void Update(RG int x){
    		sum[x] = sum[ch[0][x]] + sum[ch[1][x]] + val[x] + 1;
    	}
    
    	IL void Rotate(RG int x){
    		RG int y = fa[x], z = fa[y], c = Son(x);
    		if(!Isroot(y)) ch[Son(y)][z] = x; fa[x] = z;
    		ch[c][y] = ch[!c][x], fa[ch[c][y]] = y;
    		ch[!c][x] = y, fa[y] = x, Update(y);
    	}
    
    	IL void Splay(RG int x){
    		for(RG int y = fa[x]; !Isroot(x); Rotate(x), y = fa[x])
    			if(!Isroot(y)) Son(x) ^ Son(y) ? Rotate(x) : Rotate(y);
    		Update(x);
    	}
    
    	IL void Access(RG int x){
    		for(RG int y = 0; x; y = x, x = fa[x]){
    			Splay(x), val[x] += sum[ch[1][x]] - sum[y];
    			ch[1][x] = y, Update(x);
    		}
    	}
    
    	IL int Findroot(RG int x){
    		Access(x), Splay(x);
    		while(ch[0][x]) x = ch[0][x];
    		Splay(x);
    		return x;
    	}
    
    	IL void Link(RG int x, RG int y){
    		if(!y) return;
    		Access(y), Splay(x), Splay(y);
    		fa[x] = y, val[y] += sum[x], Update(y);
    	}
    
    	IL void Cut(RG int x, RG int y){
    		if(!y) return;
    		Access(x), Splay(x);
    		ch[0][x] = fa[ch[0][x]] = 0, Update(x);
    	}
    } T[2];
    int fa[_], n, m, col[_];
    vector <int> G[_];
    
    IL void Dfs(RG int u, RG int ff){
    	for(RG int i = 0, l = G[u].size(); i < l; ++i){
    		RG int v = G[u][i];
    		if(v == ff) continue;
    		T[1].Link(v, u), fa[v] = u;
    		Dfs(v, u);
    	}
    }
    
    int main(RG int argc, RG char *argv[]){
    	n = Input();
    	for(RG int i = 1; i <= n; ++i) col[i] = 1;
    	for(RG int i = 1; i < n; ++i){
    		RG int u = Input(), v = Input();
    		G[u].push_back(v), G[v].push_back(u);
    	}
    	Dfs(1, 0), m = Input();
    	for(RG int i = 1; i <= m; ++i){
    		RG int op = Input(), x = Input(), ff, &c = col[x];
    		if(op) T[c].Cut(x, fa[x]), c ^= 1, T[c].Link(x, fa[x]);
    		else{
    			T[c].Access(x), ff = T[c].Findroot(x);
    			if(col[ff] == c) printf("%d
    ", T[c].sum[ff]);
    			else printf("%d
    ", T[c].sum[T[c].ch[1][ff]]);
    		}
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    elasticsearch常用命令
    logstash向elasticsearch写入数据,如何指定多个数据template
    rsync 实现文件同步 (重要数据通过rsyncr把数据同步到不同的两台服务器上,这样可以防止服务器的硬盘故障导致数据丢失) 客户端同步时如果要排某个目录
    rdesktop 指定服务器的分频率
    /etc/sudoers 配置
    su 和 su
    rdesktop 源码安装
    通过show variables like ‘general_log%’可以看查询日志
    密钥登陆服务器 失败
    log_output参数是指定日志的存储方式
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/8645566.html
Copyright © 2011-2022 走看看