zoukankan      html  css  js  c++  java
  • [SHOI2014]三叉神经树

    这是一道不那么(native)(LCT)题,当然可用树剖做,不过在学(LCT),自然拿(LCT)做。
    先考虑分析一些性质。
    Q:暴力我们要怎么做?
    A:建出树来,从这个节点,一直往上跑,直到对父亲节点没有贡献。
    Q:什么时候对父亲节点有贡献呢。
    A:当父亲节点只有1个1时,你从0变成了1,当父亲节点只有2个1时,你从1变成了2。
    那么我们考虑记一个v:这个节点在树中有多少个1儿子。
    那么当一个点从0 -> 1,我们先把他的父亲(access),然后(spaly),记m1,m2为splay中儿子中在原树中最深的不为1,不为2的节点,我们考虑把这个点往下的v加一个(1),然后把m1,m2交换(这个感性理解,你发现肯定是这样的)。(注意定义是不为1,不为2。)
    于是1->0是一样的操作。
    我们直接用(LCT)做。
    有不清楚的看代码:

    [SHOI2014]三叉神经树
    #include<iostream>
    #include<cstdio>
    #define ll long long
    #define N 500005
    
    int f[3 * N],c[3 * N][2],v[3 * N],m1[3 * N],m2[3 * N],ans[3 * N],t[3 * N];
    
    #define l(x) c[x][0]
    #define r(x) c[x][1]
    
    inline bool nroot(int x){return l(f[x]) == x || r(f[x]) == x;}
    
    inline void up (int x){
    	m1[x] = m1[r(x)];
    	m2[x] = m2[r(x)];
    	if(!m1[x]){
    		if(v[x] != 1)
    		m1[x] = x;
    		else
    		m1[x] = m1[l(x)];
    	}
    	if(!m2[x]){
    		if(v[x] != 2)
    		m2[x] = x;
    		else
    		m2[x] = m2[l(x)];
    	}
    }
    
    
    inline void dn(int x,int y){v[x] = v[x] + y;ans[x] = v[x] > 1;std::swap(m1[x],m2[x]);t[x] += y;} 
     
    inline void pushdown(int x){
    if(t[x]){
    	dn(l(x),t[x]);
    	dn(r(x),t[x]);
    	t[x] = 0;
    }}
    
    ll st[N];
    
    inline void rotate(int x){
    	int y = f[x],z = f[y],k = r(y) == x,w = c[x][!k];
    	if(nroot(y))c[z][r(z) == y] = x;c[x][!k] = y;c[y][k] = w;
    	if(w)f[w] = y;f[y] = x;f[x] = z;
    	up(y),up(x);
    }
    
    inline void splay(int x){
    	ll y = x,z = 0;
    	st[++z] = y;
    	while(nroot(y))st[++z] = y = f[y];
    	while(z)pushdown(st[z -- ]);
    	while(nroot(x)){
    		ll y = f[x],z = f[y];
    		if(nroot(y))
    		rotate((l(z) == y) ^ (l(y) == x) ? x : y);
    		rotate(x);
    	}  
    	up(x);
    }
    
    inline void access(int x){
    	for(int y = 0;x;x = f[y = x]){
    		splay(x),r(x) = y,up(x);
    	}
    }
    
    struct P{int to,next;}e[N * 6]; 
    
    ll head[3 * N],cnt;
    
    inline void add(int x,int y){
    	e[++cnt].to = y;
    	e[cnt].next = head[x];
    	head[x] = cnt; 
    }
    
    ll n;
    
    inline void dfs(int u,int fa){
    	v[u] = 0;
    	for(int i = head[u];i;i = e[i].next){
    		int vi = e[i].to;
    		if(vi == fa)
    		continue;
    		dfs(vi,u);
    		v[u] += ans[vi];
    	}
    	if(u <= n)ans[u] = v[u] > 1;
    }
    
    int main(){
    	scanf("%lld",&n);
    	for(int i = 1;i <= n;++i){
    		for(int j = 1;j <= 3;++j){
    			ll x;
    			scanf("%lld",&x);
    			f[x] = i;
    			add(i,x);
    			add(x,i);
    		} 
    	}
    	for(int i = n + 1;i <= n * 3 + 1;++i)
    	scanf("%lld",&ans[i]);
    	dfs(1,0);
    	ll m;
    	ll art = ans[1];
    	scanf("%lld",&m);
    	while(m -- ){
    		ll now;
    		scanf("%lld",&now);
    		ll x = f[now];
    		ll tag = ans[now] ? -1 : 1;
    		access(x),splay(x);
    		ll w = 0;
    		w = (ans[now] ? m2[x] : m1[x]);
    		if(w){
    			splay(w);
    			dn(r(w),tag),up(r(w));
    			v[w] += tag;ans[w] = v[w] > 1;up(w); 
    		}
    		else{
    			art ^= 1,dn(x,tag),up(x);
    		}
    		ans[now] ^= 1;
    		std::cout<<art<<std::endl;
    	}
    }
    
  • 相关阅读:
    rs
    stm32f767 usoc3
    stm32f767 RTT 日志
    stm32f767 标准库 工程模板
    stm32f767 HAL 工程模板
    docker tab 补全 linux tab 补全
    docker anconda 依赖 下载 不了
    docker run 常用 指令
    linux scp 命令
    Dockerfile 常用参数说明
  • 原文地址:https://www.cnblogs.com/dixiao/p/14757360.html
Copyright © 2011-2022 走看看