zoukankan      html  css  js  c++  java
  • Codeforces741D

    dsu on tree

    题目链接

    点我跳转

    题目大意

    一棵根为 (1) 的树,每条边上有一个字符((a-v)(22)种)

    一条简单路径被称为Dokhtar-kosh当且仅当路径上的字符经过重新排序后可以变成一个回文串。

    求每个子树中最长的Dokhtar-kosh路径的长度。

    解题思路

    (dsu) (on) (tree) + 状态压缩

    1.重排后构成回文的条件为:

    ​ ①.每个字母出现的次数都为偶数 ②.一个字母出现次数为奇数,其余字母出现次数为偶数

    2.字母的范围为 a ~ z , 把其转换成二进制状态(偶数为0,奇数为1)

    ​ 那么满足回文条件的二进制为 : 00...000 , 00..001 , 00..010 , ... , 10..000

    3.维护一个从根节点到子节点u的前缀异或和数组 X

    ​ 那么 u 到 v 的简单路径的字母重排后的二进制形式为 X[u] ^ X[v]

    4.节点 u 的答案有三种可能:

    ​ ①.它的两个不同分支的节点构成的简单路径 ②.它的一个分支到它本身构成的简单路径 ③.它的子节点的 ans

    于是就可以定义 (f_x) 表示状态为 (x) 的节点的最大深度

    那么当根节点为 (rt) 时 , 子节点 (u)(rt) 产生的贡献为 ↓

    if((x[u] ^ x[rt]) == 0) ma = max(ma , dep[u] - dep[rt]); 
    rep(i , 0 , 21) if((x[u] ^ x[rt]) == (1LL << i)) ma = max(ma , dep[u] - dep[rt]);
    

    子节点 (u)(rt) 的其它分支的产生贡献为 ↓

    if(f[x[u]]) ma = max(ma , f[x[u]] + dep[u] - 2 * dep[rt]);
    rep(i , 0 , 21)
    {
    	int now = f[x[u] ^ (1LL << i)];
    	if(now) ma = max(ma , dep[u] + now - 2 * dep[rt]);
    }
    

    (rt) 由它轻子儿子传递上来的贡献为 ↓

    for(int i = head[rt] ; i ; i = edge[i].nex)
    {
    	int v = edge[i].to;
    	if(v == far || v == hson[rt]) continue ;
    	dsu(v , rt , 0);
    	ans[rt] = max(ans[rt] , ans[v]);
    }
    

    (rt) 由它重儿子传递上来的贡献为 ↓

    if(hson[rt]) dsu(hson[rt] , rt , 1) , ans[rt] = max(ans[rt] , ans[hson[rt]]) , HH = hson[rt];
    if(f[x[rt]]) ma = max(ma , f[x[rt]] - dep[rt]);
    rep(i , 0 , 21) if(f[x[rt] ^ (1LL << i)]) ma = max(ma , f[x[rt] ^ (1LL << i)] - dep[rt]);
    

    因为要计算不同分支的两点产生的贡献,所以需要先对一个分支统计完贡献后,再添加它的信息

    (事实上相同分支内的节点答案的在根节点为 (rt) 的子节点的时候就已经算过了)

    AC_Code

    #include<bits/stdc++.h>
    #define rep(i,a,n) for (int i=a;i<=n;i++)
    #define int long long
    using namespace std;
    const int N = 6e5 + 10;
    struct Edge{
    	int nex , to;
    }edge[N << 1];
    int head[N] , TOT;
    void add_edge(int u , int v)
    {
    	edge[++ TOT].nex = head[u] ;
    	edge[TOT].to = v;
    	head[u] = TOT;
    }
    int hson[N] , HH , sz[N] , dep[N] , x[N];
    int n , ma , a[N] , ans[N] , f[N * 20];
    void dfs(int u , int far , int now)
    {
    	sz[u] = 1;
    	dep[u] = dep[far] + 1;
    	x[u] = now ^ a[u];
    	for(int i = head[u] ; i ; i = edge[i].nex)
    	{
    		int v = edge[i].to;
    		if(v == far) continue ;
    		dfs(v , u , x[u]);
    		sz[u] += sz[v];
    		if(sz[v] > sz[hson[u]]) hson[u] = v;
    	}
    }
    void calc(int u , int far , int rt)
    {
    	if(f[x[u]]) ma = max(ma , f[x[u]] + dep[u] - 2 * dep[rt]);
    	if((x[u] ^ x[rt]) == 0) ma = max(ma , dep[u] - dep[rt]); 
    	rep(i , 0 , 21)
    	{
    		if((x[u] ^ x[rt]) == (1LL << i)) ma = max(ma , dep[u] - dep[rt]);
    		int now = f[x[u] ^ (1LL << i)];
    		if(now) ma = max(ma , dep[u] + now - 2 * dep[rt]);
    	}
    	for(int i = head[u] ; i ; i = edge[i].nex)
    	{
    		int v = edge[i].to;
    		if(v == far || v == HH) continue ;
    		calc(v , u , rt);
    	}
    }
    void change(int u , int far , int val)
    {
    	if(val == 1) f[x[u]] = max(dep[u] , f[x[u]]);
    	else f[x[u]] = 0; 
    	for(int i = head[u] ; i ; i = edge[i].nex)
    	{
    		int v = edge[i].to;
    		if(v == far || v == HH) continue ;
    		change(v , u , val);
    	}
    }
    void dsu(int u , int far , int op)
    {
    	for(int i = head[u] ; i ; i = edge[i].nex)
    	{
    		int v = edge[i].to;
    		if(v == far || v == hson[u]) continue ;
    		dsu(v , u , 0);
    		ans[u] = max(ans[u] , ans[v]);
    	}
    	if(hson[u]) dsu(hson[u] , u , 1) , HH = hson[u] , ans[u] = max(ans[u] , ans[hson[u]]);
    	if(f[x[u]]) ma = max(ma , f[x[u]] - dep[u]);
    	rep(i , 0 , 21) 
    	{
    		if(f[x[u] ^ (1LL << i)]) ma = max(ma , f[x[u] ^ (1LL << i)] - dep[u]);
    	} 
    	for(int i = head[u] ; i ; i = edge[i].nex)
    	{
    		int v = edge[i].to;
    		if(v == far || v == hson[u]) continue ;
    		calc(v , u , u);
    		change(v , u , 1);
    	}
    	ans[u] = max(ans[u] , ma);
    	f[x[u]] = max(f[x[u]] , dep[u]); 
    	HH = 0;
    	if(!op) 
    	{
    		ma = 0;
    		change(u , far , -1);
    	}
    }
    signed main()
    {
    	cin >> n;
    	rep(i , 2 , n)
    	{
    		int x ; char op;
    		cin >> x >> op;
    		add_edge(i , x) , add_edge(x , i);
    		a[i] = (1LL << (int)(op - 'a')); 
    	}
    	dfs(1 , 0 , 0);
    	dsu(1 , 0 , 0);
    	rep(i , 1 , n) cout << ans[i] << " 
    "[i == n]; 
    	return 0;
    }
    
  • 相关阅读:
    Fix Installing .NET Framework 3.5 failed Error Code 0x800F0954 on Windows 10
    RHEL8安装五笔输入法
    Enable EPEL and Local Repository on RHEL8
    Why is Yum Replaced by DNF?
    检查Linux服务器是否被攻击的常用命令及方法
    IDEA 主题
    IDEA 如何显示一个类中所有的方法
    Appium 安装以及安装过程中遇到的问题
    Maven 如何发布 jar 包到 Nexus 私库
    java泛型的基本使用
  • 原文地址:https://www.cnblogs.com/StarRoadTang/p/14028301.html
Copyright © 2011-2022 走看看