【cf741】D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(dsu on tree)

传送门

题意:
给出一颗以\(1\)为根的有根树,树边带有一个字符(\(a\)~\(v\))的信息。
输出对于每个结点,其子树内最长的简单路径并且满足边上的字符能够组成回文串。

思路:

  • 显然最终的答案分为两部分,子树内部的答案,经过当前根结点的答案。
  • 第一种答案很好处理。类似于点分治,主要处理第二种答案。
  • 树上路径可以考虑找到\(lca\),维护点到根节点的信息。
  • 题目中的回文串可以等价于,出现奇数次的字符不超过\(1\)个。我们将字符状压一下,那么维护点到根的信息就很方便了;同理求出两点间的信息也很方便。
  • 因为要枚举两条链中的结点,我们可以类似于树\(dp\)那样,保留之前的信息,然后枚举这条链更新答案并且更新信息。
  • 这里显然枚举时枚举轻边最优(类似于启发式合并),那么可以采用\(dsu\ on\ tree\),算法会保留重儿子的信息,我们直接暴力轻儿子即可。

根据\(dsu\ on\ tree\)算法的思想,每个结点只会被暴力到\(O(logn)\)次,所以算法的时间复杂度为\(O(nlogn)\)
感觉挺考察对\(dsu\ on\ tree\)的理解的。。细节见代码吧:

/*
 * Author:  heyuhhh
 * Created Time:  2019/11/15 16:10:20
 */
#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 5e5 + 5;
 
int n;
char s[N];
vector <int> g[N];
int dis[N], sz[N], bson[N], d[N];
int f[1 << 22];
int ans[N];
 
void dfs(int u, int fa) {
    sz[u] = 1; 
    int mx = 0;
    d[u] = d[fa] + 1;
    if(fa) dis[u] = (dis[fa] ^ (1 << (s[u] - 'a')));
    for(auto v : g[u]) {
        dfs(v, u);
        sz[u] += sz[v];
        if(sz[v] > mx) {
            mx = sz[v]; bson[u] = v;
        }
    }
}
 
int Max, D;
 
void upd(int u) {
    if(f[dis[u]]) Max = max(Max, f[dis[u]] + d[u] - D);
    for(int i = 0; i < 22; i++) if(f[dis[u] ^ (1 << i)]) {
        Max = max(Max, f[dis[u] ^ (1 << i)] + d[u] - D);
    }    
}
 
void upd2(int u) {
    f[dis[u]] = max(f[dis[u]], d[u]);
}
 
void go(int u) {
    upd(u);
    for(auto v : g[u]) go(v);
}
 
void go2(int u) {
    upd2(u);    
    for(auto v : g[u]) go2(v);   
}
 
void clear(int u) {
    f[dis[u]] = 0;
    for(auto v : g[u]) clear(v);   
}
 
void dfs2(int u, int fa, int op) {
    for(auto v : g[u]) if(v != bson[u]) dfs2(v, u, 0);
    if(bson[u]) dfs2(bson[u], u, 1);
    for(auto v : g[u]) Max = max(Max, ans[v]);
    D = 2 * d[u];
    for(auto v : g[u]) if(v != bson[u]) {
        go(v); go2(v); 
    }
    upd(u); upd2(u);
    ans[u] = Max;
    if(!op) {
        clear(u), Max = 0;
    }
}
 
void run(){
    for(int i = 2; i <= n; i++) {
        int p;
        scanf("%d %c", &p, &s[i]);
        g[p].push_back(i);
    }
    dfs(1, 0);
    dfs2(1, 0, 1);
    for(int i = 1; i <= n; i++) cout << ans[i] << " \n"[i == n];
}
 
int main() {
    while(cin >> n) run();
	return 0;
}
posted @ 2019-11-15 17:31  heyuhhh  阅读(120)  评论(0编辑  收藏  举报