【USACO 2019 February Gold】Problem 1. Cow Land Solution

Description
Cow Land 总共有 N 个不同的景点( 2≤N≤10^5 )。 一共有 n−1 条道路连接任意两个景点,这意味着任意两个景点间只有一条简单路径。

每个景点 i 都有一个享受值 ei​ ,这个值可能会改变。因为一些景点在早上更有吸引力,而其他景点在下午则更能吸引游客。

从景点 i 到景点j 的奶牛们可以欣赏从景点 i 到景点 j 的路上的所有景观。这条路线的享受值为景点i 到景点 j 的路上的所有景点(包括景点 i 和景点 j )的享受值按位进行异或运算的结果。

请帮助奶牛确定他们前往 Cow Land 旅行时计划的路线的享受值。
Input
输入的第一行包含两个整数, N,Q(1≤Q≤10^5)。

接下来一行包含 N 个整数,其中第 i 个整数 ei​ 代表景点 i 的享受值。

接下来 N−1 行,每行包含两个整数 a,b ,表示景点 a 和景点 b 之间有一条道路相连。

最后 Q 行,每行包含 3 个整数,表示一个操作,具体内容如下:

1 i v,表示将 ei​ 修改为 v 。
2 i j,表示询问从景点 i 到景点 j 的路线的享受值为多少。
Output
对于每个 2 操作,输出对应查询的结果
Sample Input
5 5
1 2 4 8 16
1 2
1 3
3 4
3 5
2 1 5
1 1 16
2 3 5
2 1 5
2 1 3
Sample Output
21
20
4
20
Data Constraint
子任务:对于 50% 的数据,没有修改操作。
Solution
裸的树剖,板子题直接切。
学树剖参考
Code

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=100005;
int n,m,cnt=0;
int a[N],head[N],fa[N],dep[N],size[N],wson[N],top[N],dfn[N],rk[N],tree[4*N];
struct node {
	int to,next;
} edge[2*N];
void add(int x,int y) {
	edge[cnt].to=y;
	edge[cnt].next=head[x];
	head[x]=cnt++;
}
void build(int now,int father) {
	fa[now]=father;
	dep[now]=dep[father]+1;
	size[now]=1;
	for(int i=head[now]; i!=-1; i=edge[i].next) {
		int son=edge[i].to;
		if(son==father)continue;
		build(son,now);
		size[now]+=size[son];
		if(size[son]>size[wson[now]])wson[now]=son;
	}
}
void dfs(int now,int tp,int father) {
	top[now]=tp;
	dfn[now]=++cnt;
	rk[cnt]=now;
	if(wson[now])dfs(wson[now],tp,now);
	for(int i=head[now]; i!=-1; i=edge[i].next) {
		int son=edge[i].to;
		if(son==wson[now]||son==father)continue;
		dfs(son,son,now);
	}
}
void build_tree(int now,int l,int r) {
	if(l==r) {
		tree[now]=a[rk[l]];
		return;
	}
	int mid=(l+r)>>1;
	build_tree(now<<1,l,mid);
	build_tree((now<<1)|1,mid+1,r);
	tree[now]=tree[now<<1]^tree[(now<<1)|1];
}
void modify(int now,int l,int r,int x,int val) {
	if(l>dfn[x])return;
	if(r<dfn[x])return;
	if(l==r) {
		a[x]=val;
		tree[now]=a[x];
		return;
	}
	int mid=(l+r)>>1;
	modify(now<<1,l,mid,x,val);
	modify((now<<1)|1,mid+1,r,x,val);
	tree[now]=tree[now<<1]^tree[(now<<1)|1];
}
int query(int now,int l,int r,int u,int v) {
	if(l>v)return 0;
	if(r<u)return 0;
	if(l>=u&&r<=v)return tree[now];
	int mid=(l+r)>>1,s=0;
	s=query(now<<1,l,mid,u,v);
	s^=query((now<<1)|1,mid+1,r,u,v);
	return s;
}
int LCA(int x,int y) {
	int sum=0;
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		sum^=query(1,1,n,dfn[top[x]],dfn[x]);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])swap(x,y);
	return sum^query(1,1,n,dfn[x],dfn[y]);
}
int main() {
	scanf("%d%d",&n,&m);
	for(int i=1; i<=n; i++)
		scanf("%d",&a[i]),head[i]=-1;
	for(int i=1; i<n; i++) {
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);
		add(v,u);
	}
	build(1,1);
	cnt=0;
	dfs(1,1,1);
	build_tree(1,1,n);
	while(m--) {
		int flag,u,v;
		scanf("%d%d%d",&flag,&u,&v);
		if(flag==1)modify(1,1,n,u,v);
		else printf("%d\n",LCA(u,v));
	}
}

猜你喜欢

转载自blog.csdn.net/MZHjr/article/details/105916038