zoukankan      html  css  js  c++  java
  • [BJOI2014]大融合

    考虑到一次答案就是两点的子树和乘积。

    我们先维护一个整个大树。

    用并查集做小树的情况,树剖做子树大小的维护。

    #include<iostream>
    #include<cstdio>
    #define ll long long 
    #define N 100005
    
    ll n,q;
    
    struct P{
    	ll opt,x,y;
    }p[N];
    
    ll cnt,head[N];
    
    struct s{
    	int to,next;
    }e[N << 1];
    
    inline void add(int x,int y){
    	e[++cnt].to = y;
    	e[cnt].next = head[x];
    	head[x] = cnt;
    }
    
    bool in[N];
    
    ll fa[N];
    
    inline void del(int x,int f){
    	in[x] = 1;
    	fa[x] = f;
    	for(int i = head[x];i;i = e[i].next){
    		int v = e[i].to;
    		if(v == f)continue;
    		del(v,x);
    	}
    }
    
    ll dfncnt;
    ll siz[N],son[N],dfn[N],dep[N],top[N];
    
    inline void dfs(int u,int f){
    	fa[u] = f;
    	siz[u] = 1;
    	fa[u] = f;
    	for(int i = head[u];i;i = e[i].next){
    		int v = e[i].to;
    		if(v == f)continue;
    		dfs(v,u);
    		siz[u] += siz[v];
    		if(siz[v] > siz[son[u]])
    		son[u] = v;
    	}
    }
    
    inline void dfs2(int u,int t){
    	top[u] = t;
    	dfn[u] = ++dfncnt;
    	if(son[u])dfs2(son[u],t);
    	for(int i = head[u];i;i = e[i].next){
    		int v = e[i].to;
    		if(v == son[u] || v == fa[u])
    		continue;
    		dfs2(v,v);
    	}
    	
    } 
    
    //tree____cut
    
    ll fi[N];
    
    inline ll find(int u){
    	return (fi[u] == u) ? u : fi[u] = find(fi[u]);
    }
    
    inline void merge(int x,int y){
    	int fx = find(x),fy = find(y);
    	fi[fy] = fx;
    }
    
    //DSU
    
    ll t[N << 1];
    
    #define lowbit(x) (x & -x)
    
    inline void change(int x,int y){
    	for(int i = x;i <= n;i += lowbit(i))
    	t[i] += y;
    }
    
    inline ll cha(int x){
    	ll ans = 0;
    	for(int i = x;i;i -= lowbit(i))
    	ans += t[i];
    	return ans;
    }
    
    //BIT
    
    int main(){
    	scanf("%lld%lld",&n,&q);
    	for(int i = 1;i <= q;++i){
    		char a ;
    		while(a != 'A' && a != 'Q')
    		a = getchar();
    		if(a == 'A')
    		p[i].opt = 1,scanf("%lld%lld",&p[i].x,&p[i].y),add(p[i].x,p[i].y),add(p[i].y,p[i].x);
    		else
    		p[i].opt = 2,scanf("%lld%lld",&p[i].x,&p[i].y);		
    		a = '.';
    	}
    	ll root = n + 1;
    	for(int i = 1;i <= n;++i){
    		if(!in[i]){
    			add(root,i);
    			add(i,root);
    			del(i,root);
    		}
    	}
    	dfs(root,0);
    	dfs2(root,root);
    	for(int i = 1;i <= n + 1;++i)
    	fi[i] = i;
    	n += 1;
    	change(1,1);
    	for(int i = 1;i <= q;++i){
    		ll x = p[i].x,y = p[i].y;
    		if(fa[x] == y)
    		std::swap(x,y);
    		if(p[i].opt == 1){
    			ll fx = find(x);
    //			std::cout<<x<<" "<<fx<<":"<<std::endl;			
    			merge(x,y);
    			ll  tag = cha(dfn[y]);
    			while(top[x] != top[fx]){
    				change(dfn[top[x]],tag);
    //				std::cout<<dfn[x]<<" "<<tag<<std::endl;
    				change(dfn[x] + 1,-tag);
    //				std::cout<<dfn[top[x]] + 1<<" "<<-tag<<std::endl;
    				x = fa[top[x]];
    			}
    			change(dfn[fx],tag);
    //			std::cout<<dfn[fx]<<" "<<tag<<std::endl;			
    			change(dfn[x] + 1,-tag);
    //			std::cout<<dfn[x] + 1<<" "<<-tag<<std::endl;			
    		}else{
    			ll ans = 0;
    			ll siza = cha(dfn[find(x)]),sizb = cha(dfn[y]);
    			ans = (siza - sizb) * sizb;
    			std::cout<<ans<<std::endl;
    		}
    	}
    }
    
  • 相关阅读:
    【模板】后缀自动机
    【模板】矩阵求逆
    【hdu5517】Triple
    【模板】多标记 LCT
    【洛谷P4172】水管局长
    【模板】LCT
    【CF786B】Legacy
    jacoco学习
    python + redis
    Python Gitlab Api 使用方法
  • 原文地址:https://www.cnblogs.com/dixiao/p/15098040.html
Copyright © 2011-2022 走看看