• [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;
    	}
    }
    
  • 相关阅读:
    viewController 不响应横竖屏转换相关消息的问题
    nsset排序
    内存相关
    技巧
    IOSTip
    iphone 资源
    IPhone 开发经验教训总结 仅供参考 (转载)
    WIN7控制面板假死
    Firefox添加web浏览端口:此地址使用了一个通常应该用于其他网页浏览的端口
    【WordPress】WXR version error when import into wordpress
  • 原文地址:https://www.cnblogs.com/dixiao/p/14757360.html
Copyright © 2020-2023  润新知