[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;
}

  

posted @ 2018-05-31 20:59  Winniechen  阅读(238)  评论(0编辑  收藏  举报