CF1878G wxhtzdy ORO Tree

题解

Posted by WrongAnswer_90's Blog on October 9, 2023

CF1878G wxhtzdy ORO Tree

image.png

设 $f(x,y)$ 表示树上 $x$ 到 $y$ 简单路径上的点权或和中 $1$ 的个数。

有一个性质:选取的 $z$ 节点一定满足它比它左边的点($l$)或者右边的点($r$)的贡献至少要多一位,即 $f(x,l)<f(x,z)$ 或 $f(y,r)<f(y,z)$,有了这个性质,问题就简单很多了。

即 $d_{i,j}$ 表示第 $i$ 个点的祖先中满足第 $j$ 位为 $1$ 的最深节点的编号,把 $x$ 到 $y$ 的路径看成 $x$ 到 $lca$ 和 $y$ 到 $lca$ 的两段,考虑 $z$ 在第一段路径上,只需要枚举 $d_{x,i}$ 和 $d_{y,i}$ 并检查是否合法(深度大于等于 LCA)然后暴力计算即可,对于 $z$ 在第二段路径上的情况同理。

代码中使用倍增实现求 $LCA$ 和一段路径的或和,复杂度为 $\mathcal O(n\log n \log V)$。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
int cnt,T,q,maxn,n,v[200001][21],d[200001][31],dep[200001],a[200001],fa[200001][21],head[200001],to[400001],nex[400001];
inline void add(int x,int y){to[++cnt]=y,nex[cnt]=head[x],head[x]=cnt;}
void dfs(int k,int fat)
{
	fa[k][0]=fat,memcpy(d[k],d[fat],sizeof(d[k])),dep[k]=dep[fat]+1,v[k][0]=a[k];
	for(int i=0;i<=30;++i)if(a[k]>>i&1)d[k][i]=k;
	for(int i=1;i<=20;++i)fa[k][i]=fa[fa[k][i-1]][i-1],v[k][i]=v[k][i-1]|v[fa[k][i-1]][i-1];
	for(int i=head[k];i;i=nex[i])if(to[i]!=fat)dfs(to[i],k);
}
inline int LCA(int x,int y)
{
	if(dep[x]>dep[y])swap(x,y);
	for(int i=20;i>=0;--i)if(dep[fa[y][i]]>=dep[x])y=fa[y][i];
	for(int i=20;i>=0;--i)if(fa[y][i]!=fa[x][i])y=fa[y][i],x=fa[x][i];
	return x==y?x:fa[x][0];
}
inline int ask(int x,int fat)
{
	int ans=0;
	for(int i=20;i>=0;--i)if(dep[fa[x][i]]>=dep[fat])ans|=v[x][i],x=fa[x][i];
	return ans|v[fat][0];
}
void mian()
{
	read(T);int x,y,lca,vx,vy;
	while(T--)
	{
		read(n),memset(head,0,sizeof(head)),cnt=0,maxn=0;
		for(int i=1;i<=n;++i)read(a[i]);
		for(int i=1;i<n;++i)read(x,y),add(x,y),add(y,x);
		dfs(1,0),read(q);
		while(q--)
		{
			read(x,y),lca=LCA(x,y),maxn=0,vx=ask(x,lca),vy=ask(y,lca);
			for(int i=0;i<=30;++i)if(d[x][i]&&dep[d[x][i]]>=dep[lca])maxn=max(maxn,__builtin_popcount(vy|ask(d[x][i],lca))+__builtin_popcount(ask(x,d[x][i])));
			for(int i=0;i<=30;++i)if(d[y][i]&&dep[d[y][i]]>=dep[lca])maxn=max(maxn,__builtin_popcount(vx|ask(d[y][i],lca))+__builtin_popcount(ask(y,d[y][i])));
			write(maxn);
		}
		puts("");
	}
}