CF840E In a Trap 题解

Codeforces
Luogu

Description.

有一颗以 \(1\) 为根的树,每个点上有一个点权 \(a_i (a_i\le n)\)
每次询问路径 \(u\)\(v\) 上最大的 \(ai \oplus \text{dis}(i,v)\),保证 \(u\)\(v\) 的祖先

Solution.

考虑值域、树同时分块,对每个点 \(x\) 处理出它往上跳 \(256\) 个数中最大的 \(a_u\oplus dis_{u,x}\oplus (i\times 2^8)\)
这样每次可以快速求出一整块到目标点的距离,而且这个距离肯定是形如 \(i\times 2^8\) 的,这由分块的方式决定。
预处理可以用 trie,但是有一种更好写的写法就是我们考虑我们需要维护的东西是 \(k\oplus (i\ll8)\) 的形式。
可以考虑先处理 \(k\oplus (255\ll8)\) 的答案,然后类似于高维前缀和。
这个高维前缀和有点特殊,更新顺序严格来说不确定,但是它取的是 \(\max\),有 \(a-x-x\le a\),所以多更新没关系。

复杂度 \(O(256n+\frac{nq}{256})\)

Coding.

点击查看代码
//是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;char c=getchar(),f=0;
	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	f?x=-x:x;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
const int N=50005;int n,q,mx[N][257],f[N],ff[N],dep[N],a[N];
struct edge{int to,nxt;}e[N<<1];int et,head[N];
inline void adde(int x,int y) {e[++et]=(edge){y,head[x]},head[x]=et;}
inline void chkmx(int &x,int y) {x<y?x=y:0;}
inline void dfs0(int x,int fa)
{
	f[x]=fa,dep[x]=dep[fa]+1;
	for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=fa) dfs0(e[i].to,x);
	if(dep[x]<256) return;else ff[x]=x;
	for(int i=0;i<256;i++) chkmx(mx[x][(a[ff[x]]>>8)^255],(a[ff[x]]^i)|(255<<8)),ff[x]=f[ff[x]];
	for(int i=0;i<8;i++) for(int j=0;j<256;j++) chkmx(mx[x][j],mx[x][j^(1<<i)]-(256<<i));
}
int main()
{
	read(n,q);for(int i=1;i<=n;i++) read(a[i]);
	for(int i=1,x,y;i<n;i++) read(x,y),adde(x,y),adde(y,x);
	for(dfs0(1,0);q--;)
	{
		int x,y,ds,u,rs=0;read(x,y),ds=dep[y]-dep[x]+1,u=y;
		for(int i=0;i<(ds>>8);i++) rs=max(rs,mx[u][i]),u=ff[u];
		for(int i=(ds>>8)<<8;i<ds;i++) rs=max(rs,a[u]^i),u=f[u];
		printf("%d\n",rs);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/pealfrog/p/15424845.html