zoukankan      html  css  js  c++  java
  • [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
    ",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;
    }
    
  • 相关阅读:
    Unity周记: 2020.09.07-09.13
    Unity周记: 2020.08.31-09.06
    CF1060F Shrinking Tree
    洛谷P6783 [Ynoi2008] rrusq
    洛谷P5644 [PKUWC2018] 猎人杀
    洛谷P1587 [NOI2016] 循环之美
    洛谷P4466 [国家集训队] 和与积
    集合幂级数杂题
    Flink基础(49):FLINK SQL(25) 内置函数(七)表值函数
    Flink基础(48):FLINK SQL(24) 内置函数(六)条件函数
  • 原文地址:https://www.cnblogs.com/JYYHH/p/9099254.html
Copyright © 2011-2022 走看看