BZOJ 3123 [Sdoi2013]森林

题解:

启发式合并主席树

时间复杂度O(nlogn*logn)

空间复杂度O(nlogn*logn)

Woc初始的时候也用了启发式合并建图,然后RE成翔了

一开始算错了空间,下次注意

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int maxn=100000;

int n,m,TT;
int a[maxn];
int lastans=0;

int cntedge=0;
int head[maxn]={0};
int to[maxn<<1]={0},nex[maxn<<1]={0};
void Addedge(int x,int y){
	nex[++cntedge]=head[x];
	to[cntedge]=y;
	head[x]=cntedge;
}


int b[maxn],nn;
struct PresidentTree{
	int ls,rs,d;
}tree[maxn*100];
int Tsize=0;
int root[maxn]={0};

void BuildTree(int &now,int l,int r){
	now=++Tsize;
	tree[now].d=0;
	if(l==r)return;
	int mid=(l+r)>>1;
	BuildTree(tree[now].ls,l,mid);
	BuildTree(tree[now].rs,mid+1,r);
}

void Updatapoint(int &now,int l,int r,int pre,int p){
	now=++Tsize;
	tree[now]=tree[pre];
	tree[now].d++;
	if(l==r)return;
	int mid=(l+r)>>1;
	if(p<=mid)Updatapoint(tree[now].ls,l,mid,tree[pre].ls,p);
	else Updatapoint(tree[now].rs,mid+1,r,tree[pre].rs,p);
}
int Queryans(int l,int r,int x,int y,int z,int t,int k){
	if(l==r)return b[l];
	int lx=tree[x].ls,ly=tree[y].ls,lz=tree[z].ls,lt=tree[t].ls;
	int d=tree[lx].d+tree[ly].d-tree[lz].d-tree[lt].d;
	int mid=(l+r)>>1;
	if(k<=d)return Queryans(l,mid,lx,ly,lz,lt,k);
	else return Queryans(mid+1,r,tree[x].rs,tree[y].rs,tree[z].rs,tree[t].rs,k-d);
}



int f[maxn][20];
int dep[maxn];
void Dfs(int x,int fa){
	dep[x]=dep[fa]+1;
	f[x][0]=fa;
	for(int j=1;j<=19;++j){
		f[x][j]=f[f[x][j-1]][j-1];
	}
	Updatapoint(root[x],1,nn,root[fa],a[x]);
	for(int i=head[x];i;i=nex[i]){
		if(to[i]==fa)continue;
		Dfs(to[i],x);
	}
}

int Getlca(int u,int v){
	if(dep[u]<dep[v])swap(u,v);
	for(int j=19;j>=0;--j){
		if(dep[f[u][j]]>=dep[v]){
			u=f[u][j];
		}
	}
	if(u==v)return u;
	for(int j=19;j>=0;--j){
		if(f[u][j]!=f[v][j]){
			u=f[u][j];v=f[v][j];
		}
	}
	return f[u][0];
}

int Getans(int u,int v,int k){
	int lca=Getlca(u,v);
	return Queryans(1,nn,root[u],root[v],root[lca],root[f[lca][0]],k);
}

int father[maxn];
int siz[maxn];
int Getf(int x){
	if(father[x]==x)return x;
	return father[x]=Getf(father[x]);
}
void Unionn(int x,int y){
	int fx=Getf(x);
	int fy=Getf(y);
	siz[fy]+=siz[fx];
	father[fx]=fy;
}

int testcase;
int main(){
	scanf("%d",&testcase);
	scanf("%d%d%d",&n,&m,&TT);
	for(int i=1;i<=n;++i){
		scanf("%d",&a[i]);
		b[i]=a[i];
	}
	sort(b+1,b+1+n);
	nn=unique(b+1,b+1+n)-b-1;
	for(int i=1;i<=n;++i)a[i]=lower_bound(b+1,b+1+nn,a[i])-b;
	BuildTree(root[0],1,nn);
	
	for(int i=1;i<=n;++i){
		father[i]=i;siz[i]=1;
	}
	while(m--){
		int x,y;
		scanf("%d%d",&x,&y);
		Addedge(x,y);
		Addedge(y,x);
		Unionn(x,y);
	}
	for(int i=1;i<=n;++i){
		if(!root[i])Dfs(i,0);
	}
	
	while(TT--){
		char opty=getchar();
		while(opty!='Q'&&opty!='L')opty=getchar();
		int x,y,z;
		scanf("%d%d",&x,&y);
		x^=lastans;y^=lastans;
		if(opty=='Q'){
			scanf("%d",&z);
			z^=lastans;
			printf("%d\n",lastans=Getans(x,y,z));
		}else{
			int fx=Getf(x);
			int fy=Getf(y);
			Addedge(x,y);
			Addedge(y,x);
			if(Getf(x)==Getf(y))exit(0);
			if(siz[fx]<siz[fy]){
				Dfs(x,y);
			}else{
				Dfs(y,x);
			}
			Unionn(x,y);
		}
	}
	return 0;
}

  

 

posted @ 2018-03-03 19:15  ws_zzy  阅读(138)  评论(0编辑  收藏  举报