[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;
		}
	}
}
原文地址:https://www.cnblogs.com/dixiao/p/15098040.html