SCOI2016 幸运数字

Description

A 国共有 n 座城市,这些城市由 n − 1 条道路相连,使得任意两座城市可以互达,且路径唯一。每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征。
  一些旅行者希望游览 A 国。旅行者计划乘飞机降落在 x 号城市,沿着 x 号城市到 y 号城市之间那条唯一的路径游览,最终从 y 城市起飞离开 A 国。在经过每一座城市时,游览者就会有机会与这座城市的幸运数字拍照,从而将这份幸运保存到自己身上。
  然而,幸运是不能简单叠加的,这一点游览者也十分清楚。他们迷信着幸运数字是以异或的方式保留在自己身上的。例如,游览者拍了 3 张照片,幸运值分别是 5,7,11,那么最终保留在自己身上的幸运值就是 9(5 xor 7 xor 11)。有些聪明的游览者发现,只要选择性地进行拍照,便能获得更大的幸运值。例如在上述三个幸运值中,只选择 5 和 11,可以保留的幸运值为 14。
  现在,一些游览者找到了聪明的你,希望你帮他们计算出在他们的行程安排中可以保留的最大幸运值是多少。

Input

  第一行包含 2 个正整数 n、q,分别表示城市的数量和旅行者数量。
  第二行包含 n 个非负整数,其中第 i 个整数 Gi 表示 i 号城市的幸运值。
  随后 n − 1 行,每行包含两个正整数 x、y,表示 x 号城市和 y 号城市之间有一条道路相连。
  随后 q 行,每行包含两个正整数 x、y,表示这名旅行者的旅行计划是从 x 号城市到 y 号城市。

Output

  输出需要包含 q 行,每行包含 1 个非负整数,表示这名旅行者可以保留的最大幸运值。

Sample Input

4 2

11 5 7 9

1 2

1 3

1 4

2 3

1 4

Sample Output

14

11

 n<=20000,q<=200000,时限6s

正解应该是点分治,跑得飞快,然而我不会……考虑树剖,(200000*log2(20000)*log2(20000)*60)/1e8=24.5s,树剖显然会被卡哈~

事实上,数据没有这么强力= =于是我们就可以卡过去A.A

#include<bits/stdc++.h>
using namespace std;
#define Inc(i,L,r) for(register int i=(L);i<=(r);++i)
#define Red(i,r,L) for(register int i=(r);i>=(L);--i)
const int N = 2e4+10;
#define ll long long
struct Tree{
	int L,r;
	ll p[67];
}t[N<<2];
int fa[N],son[N],siz[N],dep[N];
int cnt,top[N],dfn[N];
ll a[N],rpa[N];
int n,Q;
struct Graph{
	vector<int>G[N];
	inline void init(){
		scanf("%d%d",&n,&Q);
		Inc(i,1,n)scanf("%lld",&a[i]);
		Inc(i,1,n-1){
			int x,y;scanf("%d%d",&x,&y);
			G[x].push_back(y);
			G[y].push_back(x);
		}
		Inc(i,1,n)siz[i]=1;//初值 
	}
	#define to G[x][i]
	inline void dfs1(int x,int Fa,int depth){
		Inc(i,0,G[x].size()-1)if(to^Fa){
			dfs1(to,fa[to]=x,dep[to]=depth+1);
			siz[x]+=siz[to];
			if(siz[son[x]]<siz[to])son[x]=to;
		}
	}
	inline void dfs2(int x,int sp){
		top[x]=sp;
		rpa[dfn[x]=++cnt]=a[x];
		if(son[x])dfs2(son[x],sp);
		Inc(i,0,G[x].size()-1)if((to^fa[x])&&(to^son[x]))dfs2(to,to);
	}
}g;
struct SegMent_LB{
	inline void insert(int x,ll k){
		if(!k)return ;
		Red(i,62,0){
			if(!(k>>i))continue;
			if(!t[x].p[i]){t[x].p[i]=k;break;}
			k^=t[x].p[i];
		}
	}
	inline void reset(int x){
		Inc(i,0,62)t[x].p[i]=0;//清空 
	}
	#define Ls v<<1
	#define rs v<<1|1
	inline void maintain(int v,int x){//暴力合并 
		Inc(i,0,62)insert(v,t[x].p[i]);
	}
	inline void build(int v,int L,int r){
		t[v]=(Tree){L,r};
		if(L==r)return insert(v,rpa[L]),void();
		int Mid=L+r>>1;
		build(Ls,L,Mid),build(rs,Mid+1,r);
		maintain(v,Ls),maintain(v,rs);
	}
	inline void update(int v,int A,int b){
		if(t[v].L>b||t[v].r<A)return ;
		if(A<=t[v].L&&t[v].r<=b)return maintain(0,v),void();
		update(Ls,A,b),update(rs,A,b);
	}
}tl;
inline void init(){
	g.init();
	g.dfs1(1,0,0);
	g.dfs2(1,1);
	tl.build(1,1,cnt);
}
inline ll Query(int x,int y){
	int t1=top[x],t2=top[y];
	tl.reset(0);
	while(t1!=t2){
		if(dep[t1]<dep[t2])swap(x,y),swap(t1,t2);
		tl.update(1,dfn[t1],dfn[x]);
		x=fa[t1],t1=top[x];
	}
	if(dep[x]<dep[y])swap(x,y);
	tl.update(1,dfn[y],dfn[x]);
	ll ans=0;
	Red(i,62,0)if((ans^t[0].p[i])>ans)ans^=t[0].p[i];
	return ans;
}
inline void solv(){
	while(Q--){
		int x,y;scanf("%d%d",&x,&y);
		cout<<Query(x,y)<<"\n";
	}
}
int main(){
//	cout<<(100000*log2(20000)*log2(20000)*60)/1e8;
	init();
	solv();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/dancingz/article/details/81044101