BJOI2014 大融合

比较好的一个题

Description

link

支持连边和查询一条边两端的连通块的大小乘积的数据结构

Solution

原来是用 (LCT) 做的,现在用线段树合并上上

连接两条边不就是 (merge) 一下

(merge) 啥就是了个问题

直接 (dfs) 序上面连续的树的编号就比较可做了

每次搞是不能整出来 (dfs) 序的,那就离线呗

先处理出来 (dfs) 序,查询的时候标号就连续了

权值线段树存标号,所在标号的 (val)(1)

这题的费时:没有想明白权值线段树存什么(真的是阴沟翻船,并查集 (+) 离线都想出来了)

#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm{
	inline int read()
	{
		int res=0,f=1; char k;
		while(!isdigit(k=getchar())) if(k=='-') f=-1;
		while(isdigit(k)) res=res*10+k-'0',k=getchar();
		return res*f;
	} 
	const int N=1e5+10,M=5e6+10;
	struct node{
		int to,nxt;
	}e[N<<1];
	int head[N],cnt,n,T;
	inline void add(int u,int v)
	{
		e[++cnt].to=v; e[cnt].nxt=head[u];
		return head[u]=cnt,void();
	}
	int ls[M],rs[M],val[M],tot;
	inline void push_up(int x){return val[x]=val[ls[x]]+val[rs[x]],void();}
	inline void build(int &p,int l,int r,int x)
	{
		if(!p) p=++tot; if(l==r) return val[p]++,void();
		int mid=(l+r)>>1;
		if(x<=mid) build(ls[p],l,mid,x);
		else build(rs[p],mid+1,r,x);
		return push_up(p);
	}
	inline int merge(int x,int y,int l,int r)
	{
		if(!x||!y) return x+y;
		int p=++tot,mid=(l+r)>>1;
		ls[p]=merge(ls[x],ls[y],l,mid);
		rs[p]=merge(rs[x],rs[y],mid+1,r);
		return push_up(p),p;
	}
	inline int ask(int x,int l,int r,int st,int ed)
	{
		if(l<=st&&ed<=r) return val[x];
		int ans=0,mid=(st+ed)>>1;
		if(l<=mid) ans+=ask(ls[x],l,r,st,mid);
		if(r>mid) ans+=ask(rs[x],l,r,mid+1,ed);
		return ans;
	}
	bool vis[N]; int in[N],out[N],tim,id[N],dep[N];
	inline void dfs(int x,int fa)
	{
		in[x]=++tim; vis[x]=1; id[tim]=x; dep[x]=dep[fa]+1;
		for(int i=head[x];i;i=e[i].nxt)
		{
			int t=e[i].to; if(t==fa) continue;
			dfs(t,x);
		}out[x]=tim;
		return ;
	}
	string opt[N]; int x[N],y[N],fa[N],rt[N];
	inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
	signed main()
	{
		n=read(); T=read();
		for(int i=1;i<=n;++i) fa[i]=i;
		for(int i=1;i<=T;++i) 
		{
			cin>>opt[i];
			x[i]=read(); y[i]=read();
			if(opt[i][0]=='A') add(x[i],y[i]),add(y[i],x[i]);
		}
		int anc=n+1;
		for(int i=1;i<=n;++i)
		{
			if(!in[i]) tim=0,dfs(i,0);
		} 
		for(int i=1;i<=n;++i) build(rt[i],1,n,in[i]);
		for(int i=1;i<=T;++i)
		{
			if(opt[i][0]=='A') 
			{
				x[i]=find(x[i]); y[i]=find(y[i]);
				rt[x[i]]=merge(rt[x[i]],rt[y[i]],1,n);
				fa[y[i]]=x[i];
			} 
			if(opt[i][0]=='Q')
			{
				if(dep[x[i]]<dep[y[i]]) swap(x[i],y[i]);
				y[i]=find(y[i]);
				printf("%lld
",(ask(rt[y[i]],1,in[x[i]]-1,1,n)+ask(rt[y[i]],out[x[i]]+1,n,1,n))*ask(rt[y[i]],in[x[i]],out[x[i]],1,n));
			}
		}
		return 0;
	}
}
signed main(){return yspm::main();}
原文地址:https://www.cnblogs.com/yspm/p/12682148.html