[Lydsy1805月赛]对称数 BZOJ5361
分析:
这个题,还是蛮有趣的。考虑,如果l,r区间内的所有数出现奇数次,那么[l-1,r]的抑或和等于所得抑或和。
之后怎么维护呢,主席树维护区间抑或和,记得将每个点附上一个ull级别的随机数,之后抑或的结果冲突的概率就几乎没有了。
lca什么的,随便求。
剩下的,考虑二分答案,如果左区间的全为奇数个,就往右走,反之往左走。
附上代码:
#include <cstdio> #include <cmath> #include <algorithm> #include <cstdlib> #include <cstring> #include <queue> #include <iostream> using namespace std; #define N 205005 #define lson l,m,tr[rt].ls #define rson m+1,r,tr[rt].rs #define ll unsigned long long #define clear(rt) tr[rt].ls=tr[rt].rs=tr[rt].sum=0; struct node { int ls,rs; ll sum; }tr[N*20]; struct no { int to,next; }e[N<<1]; int dep[N],rot[N],fa[N],anc[N],siz[N],son[N],head[N],cnt,a[N],n,maxn,Q;ll val[N]; void add(int x,int y) { e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt; } void insert(int x,int v,ll c,int l,int r,int &rt) { rt=++cnt;clear(rt);tr[rt].sum=tr[x].sum^c; if(l==r)return;int m=(l+r)>>1; if(m>=v)tr[rt].rs=tr[x].rs,insert(tr[x].ls,v,c,lson); else tr[rt].ls=tr[x].ls,insert(tr[x].rs,v,c,rson); } void dfs1(int x,int from) { fa[x]=from,dep[x]=dep[from]+1,siz[x]=1; insert(rot[from],a[x],val[a[x]],1,maxn,rot[x]); for(int i=head[x];i!=-1;i=e[i].next) { int to1=e[i].to; if(to1!=from) { dfs1(to1,x); siz[x]+=siz[to1]; if(siz[to1]>siz[son[x]])son[x]=to1; } } } void dfs2(int x,int top) { anc[x]=top;if(son[x])dfs2(son[x],top); for(int i=head[x];i!=-1;i=e[i].next) { int to1=e[i].to; if(to1!=fa[x]&&to1!=son[x])dfs2(to1,to1); } } int get_lca(int x,int y) { while(anc[x]!=anc[y]) { if(dep[anc[x]]<dep[anc[y]])swap(x,y); x=fa[anc[x]]; } return dep[x]<dep[y]?x:y; } ll s[N]; int main() { int T; scanf("%d",&T); for(int i=1;i<=200001;i++)val[i]=(ll)rand()*rand()*rand(),s[i]=s[i-1]^val[i]; while(T--) { memset(son,0,sizeof(son));memset(head,-1,sizeof(head));cnt=0;maxn=0; scanf("%d%d",&n,&Q); for(int i=1;i<=n;i++)scanf("%d",&a[i]),maxn=max(maxn,a[i]); for(int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); add(x,y);add(y,x); } cnt=0;maxn++; dfs1(1,0);dfs2(1,1); while(Q--) { int x,y;scanf("%d%d",&x,&y); int lca=get_lca(x,y),f=fa[lca]; x=rot[x],y=rot[y],lca=rot[lca],f=rot[f]; int l=1,r=maxn; while(l<r) { int m=(l+r)>>1; if((tr[tr[x].ls].sum^tr[tr[y].ls].sum^tr[tr[lca].ls].sum^tr[tr[f].ls].sum)==(s[m]^s[l-1])) { l=m+1,x=tr[x].rs,y=tr[y].rs,lca=tr[lca].rs,f=tr[f].rs; }else { r=m,x=tr[x].ls,y=tr[y].ls,lca=tr[lca].ls,f=tr[f].ls; } } printf("%d\n",l); } } return 0; }