[Lydsy1805月赛] 对称数

    挺不错的一道数据结构题QWQ。

    一开始发现这个题如果不看数据范围的话,妥妥的树上莫队啊23333,然鹅10组数据是不可能让你舒舒服服的树上莫队卡过的23333

    于是想了想,这个题的模型就是,把u到v链上的权值出现奇偶次的01串搞出来,然后第一个0的位置就是所求。。。。。

    但是这个01串并不是很好搞,因为每一位都得异或啊。。。。这样复杂度就要乘上一个 200000/32了(bitset压位),还不如树上莫队呢QWQ

    不过有一种套路,叫做hash异或,我们就给每一个权值随机一个unsined long long范围的hash值,大概率保证询问涉及的子集的异或和不为0(这个主要看人品了。。。因为总的来说肯定会有很多子集的异或和为0,但是因为子集总数太过庞大,询问涉及的只是小部分,所以出错概率还是很小的2333)

    这样,如果一个区间所有数都出现奇数次,那么区间的hash异或起来就和 路径权值线段树在这个区间异或起来的值一样了,直接在主席树上二分即可。。。

    (注意lca是要被算上的,但是如果直接用到根前缀的两个主席树异或的话lca是会被消去的)

#include<bits/stdc++.h>
#define ll unsigned long long
using namespace std;
const int maxn=200005;
#define mid (l+r>>1)
int T,n,a[maxn],m,to[maxn*2],ne[maxn*2],dep[maxn],le,w,A,B,ans;
int hd[maxn],num,siz[maxn],son[maxn],cl[maxn],f[maxn],ri,lca;
inline void add(int x,int y){ to[++num]=y,ne[num]=hd[x],hd[x]=num;}
ll val[maxn],Xor[maxn],now;
struct node{
	ll sum;
	node *lc,*rc;
}nil[maxn*37],*rot[maxn],*cnt;

inline void init(){
	nil->sum=0;
	nil->lc=nil->rc=rot[0]=cnt=nil;
	fill(hd+1,hd+n+1,0),num=0;
	memset(son,0,sizeof(son));
}

node *update(node *u,int l,int r){
	node *ret=++cnt;
	*ret=*u,ret->sum^=val[le];
	if(l==r) return ret;
	
	if(le<=mid) ret->lc=update(ret->lc,l,mid);
	else ret->rc=update(ret->rc,mid+1,r);
	
	return ret;
}

void query(node *u,int l,int r){
	if(l>=le&&r<=ri){ now^=u->sum; return;}
	if(le<=mid) query(u->lc,l,mid);
	if(ri>mid) query(u->rc,mid+1,r);
}

void Fdfs(int x,int fa){
	f[x]=fa,siz[x]=1,dep[x]=dep[fa]+1;
	le=a[x],rot[x]=update(rot[fa],1,200001);
	
	for(int i=hd[x];i;i=ne[i]) if(to[i]!=fa){
		Fdfs(to[i],x),siz[x]+=siz[to[i]];
		if(!son[x]||siz[to[i]]>siz[son[x]]) son[x]=to[i];
	}
}

void Sdfs(int x,int tp){
	cl[x]=tp;
	if(!son[x]) return;
	
	Sdfs(son[x],tp);
	for(int i=hd[x];i;i=ne[i]) if(to[i]!=f[x]&&to[i]!=son[x]) Sdfs(to[i],to[i]);
}

int LCA(int x,int y){
	while(cl[x]!=cl[y]){
		if(dep[cl[x]]>dep[cl[y]]) x=f[cl[x]];
		else y=f[cl[y]];
	}
	return dep[x]<dep[y]?x:y;
}

void query(node *u,node *v,int l,int r){
	if(l==r){ ans=l; return;}
	
	if((u->lc->sum^v->lc->sum^((a[lca]>=l&&a[lca]<=mid)?val[a[lca]]:0))==(Xor[mid]^Xor[l-1])) query(u->rc,v->rc,mid+1,r);
	else query(u->lc,v->lc,l,mid);
}

inline void solve(){
	Fdfs(1,0),Sdfs(1,1);
	
	while(m--){
		scanf("%d%d",&A,&B),lca=LCA(A,B);
		query(rot[A],rot[B],1,200001);
		printf("%d\n",ans);
	}
}

int main(){
//	freopen("data.in","r",stdin);
//	freopen("data.out","w",stdout);
	
	val[1]=1;
	for(int i=2;i<=200001;i++) val[i]=val[i-1]*233ll;
	for(int i=1;i<=200001;i++) Xor[i]=val[i]^Xor[i-1];
	
	scanf("%d",&T);
	while(T--){
		init(),scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++) scanf("%d",a+i);
		int uu,vv;
		for(int i=1;i<n;i++) scanf("%d%d",&uu,&vv),add(uu,vv),add(vv,uu);
		
		solve();
	}
	
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/JYYHH/p/9099254.html