1. 程式人生 > >【分塊】計蒜客17120 2017 ACM-ICPC 亞洲區(西安賽區)網絡賽 G. Xor

【分塊】計蒜客17120 2017 ACM-ICPC 亞洲區(西安賽區)網絡賽 G. Xor

-i main stream 異或 cpc -1 eof wan 細節

題意:給一棵樹,每個點有權值。q次詢問a,b,k,問你從a點到b點,每次跳距離k,權值的異或和?

預處理每個點往其根節點的路徑上隔1~sqrt(n)的距離的異或和,然後把詢問拆成a->lca(a,b),lca(a,b)->b,討論一下即可,細節比較多。

隊友的代碼:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int q,a[50004],fa[50004][18],s[50004][230],nxt[100005],to[100005],head[100005],en,sq,n,vis[50004],deep[50004];
void add(int u,int v)
{
	nxt[++en]=head[u];
	head[u]=en;
	to[en]=v;
}
int get(int now,int x)
{
	for(int i=17;i>=0;--i)
	if(x>=(1<<i))
	{
		now=fa[now][i];
		x-=(1<<i);
	}
	return now;
}
void dfs(int now)
{
	vis[now]=1;
	for(int i=1;i<=17;++i)
	{
		fa[now][i]=fa[fa[now][i-1]][i-1];
	}
	for(int i=1;i<=sq;++i)
	{
		s[now][i]=s[get(now,i)][i]^a[now];
	}
	for(int i=head[now];i;i=nxt[i])
	if(!vis[to[i]])
	{
		fa[to[i]][0]=now;
		deep[to[i]]=deep[now]+1;
		dfs(to[i]);
	}
}
int lca(int u,int v)
{
	for(int i=17;i>=0;--i)
	if(deep[fa[u][i]]>=deep[v])
		u=fa[u][i];
	for(int i=17;i>=0;--i)
	if(deep[fa[v][i]]>=deep[u])
		v=fa[v][i];
	if(u==v)return u;
	for(int i=17;i>=0;--i)
	if(fa[u][i]!=fa[v][i])
	{
		u=fa[u][i];
		v=fa[v][i];
	}
	return fa[u][0];
}
int main()
{
	while(scanf("%d%d",&n,&q)!=EOF)
	{
		int u,v,k;
		for(int i=1;i<n;++i)
		{
			scanf("%d%d",&u,&v);
			add(u,v);
			add(v,u);
		}
		sq=sqrt(n);
		for(int i=1;i<=n;++i) scanf("%d",&a[i]);
		deep[1]=1;
		dfs(1);
		for(int i=1;i<=q;++i)
		{
			scanf("%d%d%d",&u,&v,&k);
			if(k<=sq)
			{
				int nowans=0;
				int l=lca(u,v);
				int l1=(deep[u]-deep[l])%k;
				int ll=get(l,k-l1);
				nowans^=s[u][k];
				nowans^=s[ll][k];
				int l2=(deep[v]-deep[l]);
				if(l2>=k-l1&&v!=l)
				{
					l2-=(k-l1);
					v=get(v,l2%k);
					l1=(deep[v]-deep[l])%k;
					if(l1==0) ll=l;
					else ll=get(l,k-l1);
					nowans^=s[v][k];
					nowans^=s[ll][k];
				}
				printf("%d\n",nowans);
			}
			else
			{
				
				int nowans=0;
				int l=lca(u,v);
				int l1=(deep[u]-deep[l])%k;
				int ll=get(l,k-l1);
				int now=u;
				while(deep[now]>=deep[l])
				{
					nowans^=a[now];
					now=get(now,k);
				}
				int l2=(deep[v]-deep[l]);
				if(l2>=k-l1&&v!=l)
				{
					l2-=(k-l1);
					v=get(v,l2%k);
					now=v;
					while(deep[now]>deep[l])
					{
						nowans^=a[now];
						now=get(now,k);
					}
				}
				printf("%d\n",nowans);
			}
		}
		en=0;
		for(int i=1;i<=n;++i)
		{
			head[i]=0;
			for(int j=1;j<=sq;++j)
				s[i][j]=0;
			a[i]=0;
			vis[i]=0;
			deep[i]=0;
			for(int j=0;j<=17;++j)
			fa[i][j]=0;
		}
	}
	return 0;
}

【分塊】計蒜客17120 2017 ACM-ICPC 亞洲區(西安賽區)網絡賽 G. Xor