• Codeforces 741D 【Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths】


    Description

    传送门


    Solution

    将字符串的路径看做二进制数,那么一个路径上的字符能重新调整成回文串的充要条件是从根到两个点的二进制数异或和为(0)或者(2)的幂。这是因为在一个回文串里,出现次数为奇数的字符只能有一个或者没有。

    那么问题现在变成(x)的子树里找最大的(dep_a + dep_b - dep_{lca(a, b)})。我们可以考虑钦定两个点的(lca)(x),最后用(x)的子树的值更新它即可。

    这样我们就有了(dsu on tree)的思路。那么如何保证两个点的(lca)就是(x)点呢?只需要一条链一条链的进行处理,这样任意两点的(lca)必然就是(x)。将二进制数为(s)的最深深度记录下来,枚举一下二进制数互相异或得到的值就行了。


    Code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    
    const int N = 500000;
    
    int head[N + 50], num, a[N + 50], n, siz[N + 50], dep[N + 50], ans[N + 50], maxson[N + 50], s[N + 50], maxv, f[N * 20], inf;
    
    struct Node
    {
    	int next, to;
    } edge[N + 50];
    
    void Addedge(int u, int v)
    {
    	edge[++num] = (Node){head[u], v};
    	head[u] = num;
    	return;
    }
    
    void Dfs1(int x, int fa)
    {
    	siz[x] = 1; dep[x] = dep[fa] + 1;
    	if (x != 1) s[x] = s[fa] ^ (1 << a[x]);
    	for (int i = head[x]; i; i = edge[i].next)
    	{
    		int v = edge[i].to;
    		Dfs1(v, x);
    		siz[x] += siz[v];
    		if (siz[v] > siz[maxson[x]]) maxson[x] = v;
    	}
    	return;
    }
    
    void Calc(int rt, int x)
    {
    	int now = s[x];
    	maxv = max(maxv, f[now] + dep[x] - 2 * dep[rt]);
    	if ((s[x] ^ s[rt]) == 0) maxv = max(maxv, dep[x] - dep[rt]);
    	for (int i = 0; i < 22; i++)
    	{
    		now = (1 << i) ^ s[x];
    		maxv = max(maxv, f[now] + dep[x] - 2 * dep[rt]);
    		if ((s[x] ^ s[rt]) == (1 << i)) maxv = max(maxv, dep[x] - dep[rt]);
    	}
    	for (int i = head[x]; i; i = edge[i].next)
    	{
    		int v = edge[i].to;
    		Calc(rt, v);
    	} 
    	return;
    }
    
    void Change(int x, int k)
    {
    	if (k) f[s[x]] = max(f[s[x]], dep[x]);
    	else f[s[x]] = inf;
    	for (int i = head[x]; i; i = edge[i].next) Change(edge[i].to, k);
    	return;
    }
    
    void Dfs2(int x, int remain)
    {
    	for (int i = head[x]; i; i = edge[i].next)
    	{
    		int v = edge[i].to;
    		if (v == maxson[x]) continue;
    		Dfs2(v, 0); 
    	}
    	if (maxson[x]) Dfs2(maxson[x], 1);
    	maxv = 0; int now = s[x];
    	maxv = max(maxv, f[now] - dep[x]);
    	for (int i = 0; i < 22; i++)
    	{
    		now = (1 << i) ^ s[x];
    		maxv = max(maxv, f[now] - dep[x]);
    	}
    	for (int i = head[x]; i; i = edge[i].next)
    	{
    		int v = edge[i].to;
    		if (v == maxson[x]) continue;
    		Calc(x, v); Change(v, 1);
    	}
    	ans[x] = maxv;
    	if (!remain) 
    	{
    		for(int i = head[x]; i; i = edge[i].next)
    			Change(edge[i].to, 0);
    		f[s[x]] = inf; 
    	}
    	else f[s[x]] = max(f[s[x]], dep[x]);
    	return;
    }
    
    void Erase(int x)
    {
    	for (int i = head[x]; i; i = edge[i].next)
    	{
    		int v = edge[i].to; Erase(v);
    		ans[x] = max(ans[x], ans[v]);
    	}
    	return;
    }
    
    int main()
    {
    	scanf("%d", &n);
    	char tmp;
    	for (int i = 2, fa; i <= n; i++)
    	{
    		scanf("%d", &fa);
    		cin >> tmp;
    		Addedge(fa, i); a[i] = tmp - 'a';
    	}
    	Dfs1(1, 0); 
    	memset(f, 128, sizeof(f)); inf = f[0];
    	Dfs2(1, 0);
    	Erase(1);
    	for (int i = 1; i <= n; i++) printf("%d ", ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    POM文件
    数据转换16进制字符
    中高分 CF 题解
    安装Java
    JNI编写,Java调用C++
    OSPF协议
    DNS协议详解
    HCIA ENSP 搭建一个简单网络 DNS解析服务器 DHCP服务器
    HTTP协议详解
    如何彻底关闭Win10自动更新,Win10永久关闭自动更新的方法
  • 原文地址:https://www.cnblogs.com/Tian-Xing-Sakura/p/13097708.html
Copyright © 2020-2023  润新知