这种算法能够解决关于询问一棵树的子树的相关信息的问题。
算法的流程大概是这样:
1、dfs将一棵树建好,将节点的size、dfs序、重儿子、该dfs序对应的节点这些信息处理好(其他的信息具体问题具体分析)。
2、进入solve函数,先去解决非重儿子,然后将这些非重儿子的信息暴力清空。
3、接下来解决重儿子,这次不清空。
4、然后再将非重儿子的信息再暴力添加。
5、将该节点的信息添加进容器。
6、回答关于这个节点的问题。
7、返回。
当然对于存信息的sum不一定是普通的数组,可能是map,可能是树状数组这类既支持插入又支持删除的容器,有适合的数据结构,而不是用数据结构去套题。
复杂度:
对于某个叶子节点来说,我们最终是要把它对答案的贡献加到根节点中,从而回答根节点的询问。可以知道,所有的节点其实都在重链上,
叶子节点到根节点的最多经过logn条轻边,我在将这个节点合并到根的时候,也顺便将别的节点合并到根上了,每合并一次,复杂度最多O(n)。
总的复杂度应该是O(nlogn)。
例题:
Codeforces 1009F
#include<bits/stdc++.h> using namespace std; const int maxn = 1e6 + 5; int deep[maxn],num[maxn],son[maxn],ans[maxn],n,mx; map<int,int> mp; vector<int> graph[maxn]; void init(){ memset(son,-1,sizeof(son)); } void add(int cur,int fa){ mp[deep[cur]] += 1; if(mp[deep[cur]] > mp[mx] || (mp[deep[cur]] == mp[mx] && deep[cur] < mx)) mx = deep[cur]; for(int i = 0;i < graph[cur].size();++i){ int v = graph[cur][i]; if(v == fa) continue; add(v,cur); } } void dfs(int cur,int fa){ for(int i = 0;i < graph[cur].size();++i){ int v = graph[cur][i]; if(v == fa || son[cur] == v) continue; dfs(v,cur); mp.clear(); mx = 0; } if(son[cur] != -1) dfs(son[cur],cur); for(int i = 0;i < graph[cur].size();++i){ int v = graph[cur][i]; if(v == fa || son[cur] == v) continue; add(v,cur); } mp[deep[cur]] += 1; if(mp[deep[cur]] > mp[mx] || (mp[deep[cur]] == mp[mx] && deep[cur] < mx)) mx = deep[cur]; ans[cur] = mx - deep[cur]; } void dfs1(int cur,int fa,int d){ deep[cur] = d; num[cur] = 1; for(int i = 0;i < graph[cur].size();++i){ int v = graph[cur][i]; if(v == fa) continue; dfs1(v,cur,d + 1); num[cur] += num[v]; if(son[cur] == -1 || num[son[cur]] < num[v]) son[cur] = v; } } int main(){ scanf("%d",&n); for(int i = 0;i < n - 1;++i){ int from,to; scanf("%d%d",&from,&to); graph[from].push_back(to); graph[to].push_back(from); } init(); dfs1(1,0,1); dfs(1,0); for(int i = 1;i <= n;++i) printf("%d ",ans[i]); return 0; }
Codeforces 600E
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int maxn = 1e5 + 5; LL color[maxn],ans[maxn]; map<LL,int> mp; map<int,LL> mp2; vector<int> graph[maxn]; int deep[maxn],num[maxn],son[maxn],mx; //map<LL,int>::iterator iter; void add(int cur,int fa){ int keep = ++mp[color[cur]]; if(keep > mx) mx = keep; mp2[keep] += color[cur]; for(int i = 0;i < graph[cur].size();++i){ int v = graph[cur][i]; if(v == fa) continue; add(v,cur); } } void dfs(int cur,int fa){ for(int i = 0;i < graph[cur].size();++i){ int v = graph[cur][i]; if(v == son[cur] || v == fa) continue; dfs(v,cur); mp.clear(); mp2.clear(); mx = 0; } if(son[cur] != -1) dfs(son[cur],cur); for(int i = 0;i < graph[cur].size();++i){ int v = graph[cur][i]; if(son[cur] == v || v == fa) continue; add(v,cur); } int keep = ++mp[color[cur]]; if(keep > mx) mx = keep; mp2[keep] += color[cur]; ans[cur] = mp2[mx]; } void dfs1(int cur,int fa,int d){ deep[cur] = d; num[cur] = 1; for(int i = 0;i < graph[cur].size();++i){ int v = graph[cur][i]; if(v == fa) continue; dfs1(v,cur,d + 1); num[cur] += num[v]; if(son[cur] == -1 || num[v] > num[son[cur]]) son[cur] = v; } } int main(){ int n; scanf("%d",&n); for(int i = 1;i <= n;++i) scanf("%lld",&color[i]); memset(son,-1,sizeof(son)); int from,to; for(int i = 0;i < n - 1;++i){ scanf("%d%d",&from,&to); graph[from].push_back(to); graph[to].push_back(from); } dfs1(1,0,1); dfs(1,0); for(int i = 1;i <= n;++i) printf("%lld%c",ans[i],i == n ? ' ' : ' '); return 0; }
Codeforces 570D
#include<bits/stdc++.h> using namespace std; const int maxn = 5e5 + 5; struct query{ int id,h; query(int a = 0,int b = 0){ id = a,h = b; } }; int deep[maxn],son[maxn],num[maxn],color[maxn],n,m; char str[maxn]; bool ans[maxn]; map<int,int> mp; vector<int> graph[maxn]; vector<query> ask[maxn]; inline int cnt1(int x){ int ret = 0; while(x){ x = x & (x - 1); ++ret; } return ret; } void add(int cur,int fa){ mp[deep[cur]] ^= (1<<color[cur]); for(int i = 0;i < graph[cur].size();++i){ int v = graph[cur][i]; if(v == fa) continue; add(v,cur); } } void dfs(int cur,int fa){ for(int i = 0;i < graph[cur].size();++i){ int v = graph[cur][i]; if(v == fa || v == son[cur]) continue; dfs(v,cur); mp.clear(); } if(son[cur] != -1) dfs(son[cur],cur); for(int i = 0;i < graph[cur].size();++i){ int v = graph[cur][i]; if(v == fa || v == son[cur]) continue; add(v,cur); } mp[deep[cur]] ^= (1<<color[cur]); for(int i = 0;i < ask[cur].size();++i){ query q = ask[cur][i]; int id = q.id,h = q.h; int mask = mp[h]; int cnt = cnt1(mask); ans[id] = (cnt <= 1); } } void dfs1(int cur,int fa,int d){ num[cur] = 1; deep[cur] = d; for(int i = 0;i < graph[cur].size();++i){ int v = graph[cur][i]; if(v == fa) continue; dfs1(v,cur,d + 1); num[cur] += num[v]; if(son[cur] == -1 || num[son[cur]] < num[v]) son[cur] = v; } } int main(){ scanf("%d%d",&n,&m); int fa; for(int i = 2;i <= n;++i){ scanf("%d",&fa); graph[i].push_back(fa); graph[fa].push_back(i); } scanf("%s",str + 1); for(int i = 1;i <= n;++i) color[i] = str[i] - 'a'; for(int i = 0;i < m;++i){ int vi,hi; scanf("%d%d",&vi,&hi); ask[vi].push_back(query(i,hi)); } memset(son,-1,sizeof(son)); dfs1(1,0,1); dfs(1,0); for(int i = 0;i < m;++i){ printf("%s ",ans[i] ? "Yes" : "No"); } }