DTOJ#1379. 森林(forest)

小z有一片森林,含有 N N N 个节点,每个节点上都有一个非负整数作为权值。 初始的时候,森林中有 M M M 条边。

小z希望执行 T T T 个操作,操作有两类:

  • Q   x   y   k Q~x~y~k Q x y k 查询点 x x x 到点 y y y 路径上所有的权值中,第 k k k 小的权值是多少。此操作保证点 x x x 和点 y y y 连通,同时这两个节点的路径上至少有 k k k 个点

  • L   x   y L~x~y L x y 在点 x x x 和点 y y y 之间连接一条边。保证完成此操作后,仍然是一片森 林。

为了体现程序的在线性,我们把输入数据进行了加密。设 l a s t a n s lastans lastans 为程序上 一次输出的结果,初始的时候 l a s t a n s lastans lastans 0 0 0

对于一个输入的操作 Q   x   y   k Q~x~y~k Q x y k ,其真实操作为 Q   x ⊕ l a s t a n s   y ⊕ l a s t a n s   k ⊕ l a s t a n s Q~x \oplus lastans~y \oplus lastans~k \oplus lastans Q xlastans ylastans klastans

对于一个输入的操作 L   x   y L~x~y L x y ,其真实操作为 L   x ⊕ l a s t a n s   y ⊕ l a s t a n s L~x \oplus lastans~ y \oplus lastans L xlastans ylastans

其中 ⊕ \oplus 运算符表示异或。 请写一个程序来帮助小z完成这些操作。

第一行包含一个正整数 t e s t c a s e testcase testcase,表示当前测试数据的测试点编号。保证 1 ≤ t e s t c a s e ≤ 20 1 \le testcase \le 20 1testcase20

第二行包含三个整数 N , M , T N,M,T N,M,T,分别表示节点数、初始边数、操作数。

第三行包含 N N N 个非负整数表示 N N N 个节点上的权值。

接下来 M M M 行,每行包含两个整数 x x x y y y ,表示初始的时候,点 x x x 和点 y y y 之 间有一条无向边。

接下来 T T T行,每行描述一个操作,格式为“ Q   x   y   k   Q~ x~y~k~ Q x y k ”或者“ L   x   y L~x~ y L x y",其含义 见题目描述部分。

对于每一个第一类操作,输出一个非负整数表示答案。

样例输入

1 
8  4 8
1  1 2 2 3 3 4 4
4  7
1  8
2  4
2  1
Q 8 7 3
Q 3 5 1 
Q 10 0 0 
L 5 4 
L 3 2
L 0 7 
Q 9 2 5
Q 6 1 6 

样例输出

2
2
1
4
2

sdoi2013
题解:
考虑若不连边,那么树上主席树直接跑。但是连边就很麻烦。于是考虑启发式合并,每次暴力重构

#include<bits/stdc++.h>
#define N 80004
using namespace std;
/*inline int read(){
	int x=0;char s=getchar();
	while(s<'0'||s>'9')s=getchar();
	while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
	return x;
}*/

int btot,head[N],ver[N<<1],nex[N<<1];
inline void add(int x,int y){
    
    
	nex[++btot]=head[x];head[x]=btot;ver[btot]=y;
}

int a[N],b[N],bt,root[N],f[N][21],dep[N],TT=20,fa[N],size[N];

struct seg{
    
    
	int ls,rs,sum;
}t[10000007];
int tot;
int change(int p,int q,int l,int r,int tl,int val){
    
    
	t[p]=t[q];
	if(l==r){
    
    
		t[p].sum+=val;
		return p;
	}
	int mid=(l+r)>>1;
	if(tl<=mid)t[p].ls=change(++tot,t[q].ls,l,mid,tl,val);
	else t[p].rs=change(++tot,t[q].rs,mid+1,r,tl,val);
	t[p].sum=t[t[p].ls].sum+t[t[p].rs].sum;
	return p;
}
int ask(int p1,int p2,int q1,int q2,int l,int r,int kk){
    
    
	if(l==r)return l;
	int mid=(l+r)>>1,sum=t[t[q1].ls].sum+t[t[q2].ls].sum-t[t[p1].ls].sum-t[t[p2].ls].sum;
	if(sum<kk)return ask(t[p1].rs,t[p2].rs,t[q1].rs,t[q2].rs,mid+1,r,kk-sum);
	else return ask(t[p1].ls,t[p2].ls,t[q1].ls,t[q2].ls,l,mid,kk);
}
inline void init(){
    
    
	tot=0;btot=0;bt=0;t[0].ls=t[0].rs=t[0].sum=0;
	memset(head,0,sizeof(head));
	//memset(f,0,sizeof(f));
	//memset(dep,0,sizeof(dep));
}
inline void test(int p,int l,int r){
    
    
	cout<<l<<" "<<r<<":"<<t[p].sum<<endl;
	int mid=(l+r)>>1;
	if(l==r||!p)return ;
	test(t[p].ls,l,mid);test(t[p].rs,mid+1,r);
}
void dfs(int x,int las){
    
    
	for(int i=head[x];i;i=nex[i]){
    
    
		int y=ver[i];
		if(y==las)continue;
		f[y][0]=x;dep[y]=dep[x]+1;
		for(int j=1;j<=TT;++j)f[y][j]=f[f[y][j-1]][j-1];
		root[y]=change(++tot,root[x],1,bt,a[y],1);
		dfs(y,x);
	}
}
inline int get(int x){
    
    
	if(fa[x]==x)return x;
	return fa[x]=get(fa[x]);
}
void dfs2(int x,int las){
    
    
	for(int i=head[x];i;i=nex[i]){
    
    
		int y=ver[i];
		if(y==las)continue;
		f[y][0]=x;dep[y]=dep[x]+1;
		fa[y]=x;size[get(y)]++;
		for(int j=1;j<=TT;++j)f[y][j]=f[f[y][j-1]][j-1];
		root[y]=change(++tot,root[x],1,bt,a[y],1);
		dfs2(y,x);
	}
}
inline int get_lca(int x,int y){
    
    
	if(dep[x]>dep[y])swap(x,y);
	for(int i=TT;i+1;--i)if(dep[f[y][i]]>=dep[x])y=f[y][i];
	if(x==y)return x;
	for(int i=TT;i+1;--i)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
	return f[x][0];
}
inline int num(int x){
    
    return lower_bound(b+1,b+1+bt,x)-b;}
inline void test(int n){
    
    
	for(int i=1;i<=n;++i){
    
    
		for(int j=0;j<=2;++j){
    
    
			cout<<i<<" "<<j<<" "<<f[i][j]<<endl;
		}
	}
}
int main(){
    
    
//	freopen("P3302_2.in","r",stdin);
//	freopen("test.out","w",stdout);
	int T;
	while(scanf("%d",&T)!=EOF){
    
    
		init();
	//	cout<<T<<endl;
		int n,m,t;scanf("%d%d%d",&n,&m,&t);
	//	cout<<n<<" "<<m<<" "<<t<<endl;
		for(int i=1;i<=n;++i)scanf("%d",&a[i]),b[++bt]=a[i];
		for(int i=1;i<=n;++i)fa[i]=i,size[i]=1;
		for(int i=1;i<=m;++i){
    
    
			int x,y;scanf("%d%d",&x,&y);
			add(x,y);add(y,x);
		}
		sort(b+1,b+1+bt);bt=unique(b+1,b+1+bt)-b-1;
		for(int i=1;i<=n;++i)a[i]=num(a[i]);
		int lans=0;
		for(int i=1;i<=n;++i){
    
    
			if(!dep[i]){
    
    
				root[i]=change(++tot,root[0],1,bt,a[i],1);
				dep[i]=1;
				dfs2(i,0);
			}
		}
		
		for(int i=1;i<=t;++i){
    
    
			char c[3];scanf("%s",c);
			if(c[0]=='L'){
    
    
				int x,y,fx,fy;
				scanf("%d%d",&x,&y);
				x^=lans,y^=lans;
				fx=get(x),fy=get(y);
				
				if(size[fx]<size[fy])swap(x,y),swap(fx,fy);
				//cout<<x<<" "<<y<<" "<<fx<<" "<<fy<<endl;
				//cout<<size[fx]<<" "<<size[fy]<<endl;
				fa[fy]=fx;size[fx]+=size[fy];
				add(x,y);add(y,x);
				root[y]=change(++tot,root[x],1,bt,a[y],1);
				dep[y]=dep[x]+1;f[y][0]=x;
				for(int j=1;j<=TT;++j)f[y][j]=f[f[y][j-1]][j-1];
				dfs(y,x);
			}else{
    
    
				int x,y,k,lca;
				scanf("%d%d%d",&x,&y,&k);x^=lans,y^=lans,k^=lans;lca=get_lca(x,y);
				//cout<<x<<" "<<y<<" "<<k<<" "<<lca<<endl;
				lans=ask(root[f[lca][0]],root[lca],root[x],root[y],1,bt,k);
				lans=b[lans];
				printf("%d\n",lans);
			}
			//cout<<"-1"<<endl;
		}
		//test(n);
	}
	return 0;
}
/*
1
8 4 8
1 1 2 2 3 3 4 4
4 7
1 8
2 4
2 1
Q 8 7 3
Q 3 5 1
Q 10 0 0
L 5 4
L 3 2
L 0 7
Q 9 2 5
Q 6 1 6


*/

猜你喜欢

转载自blog.csdn.net/CSDNzhanghongyu/article/details/109525455