很好的模板題。
傳送到Codeforces:(* ̄3 ̄)╭php
首先要會DSU on Tree,不會的看這裏:(❤ ω ❤)。
衆所周知DSU on Tree是能夠用來處理子樹信息的,可是有時候也能夠用來處理鏈上信息。
IOI 2011 Race是一道著名的點分治模板題,要求統計鏈信息,也能夠用DSU on Tree來作,題目連接在這裏:(✿◕‿◕✿)。
基本思路和點分治是同樣的,對於每一個點u,咱們統計出全部通過u的路徑的信息。
因而咱們有了一個很是好的思路:統計每一個點u的時候,咱們記錄下u的全部子孫節點到u的信息,放在某個數組裏面。
以這道題爲例子,咱們把每一個字符串壓縮爲一個二進制串,而後就能夠記錄u的每一個後繼節點到u的路徑所造成的字符串。
可是問題來了,咱們要保留重兒子的信息,可是節點u和她的重兒子之間有一個字母,咱們要把這個字母加到重兒子的全部後繼節點上,這不是就退化成了暴力了麼?
對於IOI 2011 Race這樣的題,咱們能夠選擇用數據結構維護,因而複雜度多了一個log。
固然還有更簡單的作法,對於本題和IOI 2011 Race這樣的題,鏈上的信息是可減的,因而咱們能夠不保存「後繼節點到點u」的信息,而是保存「後繼節點到根」的信息,而後在統計的時候再減去「u到根的信息」。
每一個節點到根的信息是不會變的,就不須要維護了,又由於路徑信息可減,因此處理起來也很方便。
固然,對於不可減的路徑信息,能夠選擇用數據結構維護。
固然,若是維護不了的話仍是寫好寫好調的點分治吧qwq。node
#include <cstring> #include <cstdio> #include <algorithm> using namespace std; const int MAXN = 500010; const int INF = 0x3f3f3f3f; int _w; int n, ans[MAXN]; namespace G { int head[MAXN], nxt[MAXN], to[MAXN], val[MAXN], eid; void init() { memset(head, -1, sizeof head); } void adde( int u, int v, int w ) { to[eid] = v, val[eid] = w; nxt[eid] = head[u], head[u] = eid++; } } int sz[MAXN], dep[MAXN], pa[MAXN], son[MAXN], str[MAXN]; int prelude( int u, int fa, int d, int s ) { using namespace G; sz[u] = 1, dep[u] = d, pa[u] = fa, str[u] = s; for( int i = head[u]; ~i; i = nxt[i] ) { int v = to[i], t = 1<<val[i]; sz[u] += prelude(v, u, d+1, s^t); if( sz[v] > sz[son[u]] ) son[u] = v; } return sz[u]; } int maxd[1<<22]; void ans_node( int s, int d, int &ans ) { ans = max(ans, d + maxd[s]); for( int i = 0; i < 22; ++i ) ans = max(ans, d + maxd[s^(1<<i)]); } void dfs_ans( int u, int &ans ) { using namespace G; ans_node(str[u], dep[u], ans); for( int i = head[u]; ~i; i = nxt[i] ) dfs_ans(to[i], ans); } void ins_node( int s, int d ) { maxd[s] = max(maxd[s], d); } void dfs_ins( int u ) { using namespace G; ins_node(str[u], dep[u]); for( int i = head[u]; ~i; i = nxt[i] ) dfs_ins(to[i]); } void del_node( int s ) { maxd[s] = -INF; } void dfs_del( int u ) { using namespace G; del_node(str[u]); for( int i = head[u]; ~i; i = nxt[i] ) dfs_del(to[i]); } void solve( int u, bool clr ) { using namespace G; for( int i = head[u]; ~i; i = nxt[i] ) if( to[i] != son[u] ) solve(to[i], 1); if( son[u] ) solve(son[u], 0); ans_node(str[u], dep[u], ans[u]); ins_node(str[u], dep[u]); for( int i = head[u]; ~i; i = nxt[i] ) if( to[i] != son[u] ) { dfs_ans(to[i], ans[u]); dfs_ins(to[i]); } if( clr ) dfs_del(u); ans[u] -= dep[u] + dep[u]; for( int i = head[u]; ~i; i = nxt[i] ) ans[u] = max(ans[u], ans[to[i]]); ans[u] = max(ans[u], 0); } int main() { _w = scanf( "%d", &n ); G::init(); for( int i = 2; i <= n; ++i ) { int pa; char ch; _w = scanf( "%d %c", &pa, &ch ); G::adde(pa, i, ch - 'a'); } for( int i = 0; i < (1<<22); ++i ) maxd[i] = -INF; prelude(1, 0, 1, 0), solve(1, 0); for( int i = 1; i <= n; ++i ) printf( "%d ", ans[i] ); puts(""); return 0; }