【SDOI2013】【主席树】【启发式合并】森林

【描述】
在这里插入图片描述

【思路】

首先如果没有2操作,我们可以使用主席树轻松完成,这就是count on a tree。考虑2操作,我们要合并两棵树。这时我们可以利用启发式合并。每次暴力把小的一棵树搜索一次,同时加入大的一棵树的主席树中,同时更新倍增维护LCA。这样就实现了合并。对于每一个点,这样的合并不会超过 O ( l o g n ) O(logn) 次。所以时间复杂度和空间复杂度都是 O ( n l o g 2 n ) O(nlog^2n)
代码:

#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define re register
using namespace std;
const int N=1e5+5;
tr1::unordered_map<int,int>lsr;
inline int red(){
    int data=0;bool w=0; char ch=getchar();
    while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
    if(ch=='-') w=1,ch=getchar();
    while(ch>='0' && ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
    return w?-data:data;
}
int n,las=0,cnt=0,q,m,a,b[N],c,dep[N],fa[N][17],sz[N],col[N],siz[N*205|1],rt[N],to[N<<1|1],f[N],nxp[N<<1|1],tot=0,ch[N*205|1][2],val[N];
inline int copy(int v){int u=++tot;ch[u][0]=ch[v][0];ch[u][1]=ch[v][1];siz[u]=siz[v];return tot;}
inline void add(int&u,int v,int l,int r,int w){
	u=copy(v);++siz[u];
	if(l==r)return;int mid=(l+r)>>1;
	if(w<=mid)add(ch[u][0],ch[v][0],l,mid,w);
	else add(ch[u][1],ch[v][1],mid+1,r,w);
}
inline int query(int u,int v,int l1,int l2,int l,int r,int k){
	if(l==r)return l;int mid=(l+r)>>1,size=siz[ch[u][0]]+siz[ch[v][0]]-siz[ch[l1][0]]-siz[ch[l2][0]];
	if(size>=k)return query(ch[u][0],ch[v][0],ch[l1][0],ch[l2][0],l,mid,k);
	else return query(ch[u][1],ch[v][1],ch[l1][1],ch[l2][1],mid+1,r,k-size);
}
void dfs(int u,int ff,const int&cl){
	dep[u]=dep[ff]+1;fa[u][0]=ff;col[u]=cl;
	add(rt[u],rt[ff],1,n,lsr[val[u]]);
	for(int re i=1;i<17;++i)
		fa[u][i]=fa[fa[u][i-1]][i-1];
	for(int re i=f[u];i;i=nxp[i])
		if(to[i]!=ff)dfs(to[i],u,cl);
}
inline void add(int u,int v){
	to[++cnt]=v;nxp[cnt]=f[u];f[u]=cnt;
	to[++cnt]=u;nxp[cnt]=f[v];f[v]=cnt;
	if(sz[col[u]]<sz[col[v]])u^=v^=u^=v;
	sz[col[u]]+=sz[col[v]];
	dfs(v,u,col[u]);
}
inline int lca(int u,int v){
	if(dep[u]<dep[v])u^=v^=u^=v;
	int t=dep[u]-dep[v];
	for(int re i=0;(1<<i)<=t;++i)
		if(t&(1<<i))u=fa[u][i];
	if(u==v)return u;
	for(int re i=16;~i;--i)
		if(fa[u][i]!=fa[v][i])
			u=fa[u][i],v=fa[v][i];
	return fa[u][0];
}char s[5];
int main(){red();
	n=red();m=red();q=red();
	for(int re i=1;i<=n;i++)b[i]=val[i]=red();
	sort(b+1,b+n+1);int all=unique(b+1,b+n+1)-b-1;
	for(int re i=1;i<=all;i++)lsr[b[i]]=i;
	for(int re i=1;i<=n;i++)add(rt[i],0,1,n,lsr[val[i]]),dep[i]=1,col[i]=i,sz[i]=1;
	for(int re i=1;i<=m;i++)add(red(),red());
	while(q--){
		scanf("%s",s);int u=red()^las,v=red()^las;
		if(s[0]=='Q'){int lc=lca(u,v);
			cout<<(las=b[query(rt[u],rt[v],rt[lc],rt[fa[lc][0]],1,n,red()^las)])<<"\n"; 
		}else add(u,v);
	}
}
发布了106 篇原创文章 · 获赞 22 · 访问量 5486

猜你喜欢

转载自blog.csdn.net/weixin_44111457/article/details/102655319
今日推荐