P8511 [Ynoi Easy Round 2021] TEST_68

比较容易的一道 Ynoi。

可以发现,很多点的答案就是整棵树取两点异或的最大值。或者说,设整棵树异或最大的两点为 u,vu,v,那么对于所有 ii,以 ii 为根的子树不包含 uu 且不包含 vv,那么 ansi=auavans_i = a_u \oplus a_vaa 是点权。

那么哪些点为根的子树包含 uuvv 呢?可以发现包含 uu 的是 1u1 \sim u 的路径,包含 vv 的是 1v1 \sim v 的路径,均是一条链。

所以考虑两次 DFS 分别处理 1u1 \sim u1v1 \sim v,从根开始,每次先选不在路径上面的 DFS,在字典树上动态插入维护最大值。然后走路径上的点直接算答案,复杂度 O(nlogv)O(n \log v)

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std;

const int N = 5e5 + 5, M = 5e7 + 5;;

vector<int> G[N];
int n;
long long ans[N], a[N];

inline string get_two(long long x)
{
	string g;
	while (x)
	{
		g += (x & 1) + '0';
		x >>= 1;
	}
	while (g.size() < 60) g += '0';
	reverse(g.begin(), g.end());
	return g;
}

class Trie
{
public:
	int tr[M][2], idx;
	long long res;
	int nowu, nowv, rt;
	int id[M];
	void clear()
	{
		for (int i = 0; i <= idx; i++)
		{
			id[i] = 0;
			tr[i][0] = tr[i][1] = 0;
		}
		idx = 0;
		nowu = nowv = 0;
		res = 0;
		rt = 0;
	}
	void insert(int u)
	{
		long long val = a[u];
		int ux = rt, nu = u, nv = 0;
		string bt = get_two(val);
		long long c = 59, nres = 0;
		for (int i = 0; i < bt.size(); i++)
		{
			int ng = bt[i] == '0' ? 1 : 0;
			if (tr[ux][ng])
			{
				ux = tr[ux][ng];
				nres += 1LL << c;
			}
			else
			{
				ux = tr[ux][!ng];
			}
			c--;
		}
		nv = id[ux];
		if (nv && nres > res)
		{
			nowu = nu, nowv = nv;
			res = nres;
		}
		ux = rt;
		for (int i = 0; i < bt.size(); i++)
		{
			int j = bt[i] - '0';
			if (!tr[ux][j]) tr[ux][j] = ++idx;
			ux = tr[ux][j];
		}
		id[ux] = u;
	}
}a1;

int ru, rv, fa[N];

bool isin[N];

void pre_work()
{
	for (int i = 1; i <= n; i++)
	{
		a1.insert(i);
	}
	ru = a1.nowu, rv = a1.nowv;
	int rru = ru;
	do
	{
		isin[ru] = 1;
		ru = fa[ru];
	} while (ru);
	int rrv = rv;
	do
	{
		isin[rv] = 1;
		rv = fa[rv];
	} while (rv);
	ru = rru, rv = rrv;
	for (int i = 1; i <= n; i++)
	{
		if (!isin[i]) ans[i] = a1.res;
	}
	memset(isin, 0, sizeof isin);
}

void dfs1(int u, int f)
{
	if (isin[u]) ans[u] = a1.res;
	a1.insert(u);
	int cs = 0;
	for (int j : G[u])
	{
		if (j != f && !isin[j])
		{
			dfs1(j, u);
		}
		else if (j != f && isin[j]) cs = j;
	}
	if (cs) dfs1(cs, u);
}

int main()
{
	scanf("%d", &n);
	for (int i = 2; i <= n; i++)
	{
		scanf("%d", &fa[i]);
		G[fa[i]].emplace_back(i);
	}
	for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
	pre_work();
	int rru = ru;
	do
	{
		isin[ru] = 1;
		ru = fa[ru];
	} while (ru);
	ru = rru;
	a1.clear();
	dfs1(1, 1);
	memset(isin, 0, sizeof isin);
	int rrv = rv;
	do
	{
		isin[rv] = 1;
		rv = fa[rv];
	} while (rv);
	rv = rrv;
	a1.clear();
	dfs1(1, 1);
	for (int i = 1; i <= n; i++) printf("%lld\n", ans[i]);
	return 0;
}
posted @   HappyBobb  阅读(4)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示