参考链接:https://blog.csdn.net/qq_43472263/article/details/104150940
U41492 树上数颜色 https://www.luogu.com.cn/problem/U41492
求子树的颜色数有多少种
/*
U41492 树上数颜色
计算v的子树中颜色有多少种
*/
#include
#define rep(i,a,b) for(int i = a;i <= b;i++)
#define pb push_back
using namespace std;
const int N = 100010;
int sz[N],son[N];//字树大小、重儿子编号
int col[N],ans[N],now,cnt[N];//i点的颜色,第i个问题的答案,当前颜色数,i颜色的数量
vector<int>G[N];
void dfs(int u,int f){ //找重儿子
sz[u] = 1;
for(auto v : G[u]){
if(v == f)continue;
dfs(v,u);
sz[u] += sz[v];
if(!son[u] || sz[v] > sz[son[u]]){
son[u] = v;
}
}
}
void solve(int u,int f,int op){ //暴力更新答案,op = 1为增加答案,op = -1为减少答案
cnt[col[u]] += op;
if(op == 1 && cnt[col[u]] == 1)now++;
if(op == -1 && cnt[col[u]] == 0)now--;
for(auto v : G[u]){
if(v == f)continue;
solve(v,u,op);
}
}
void dfs2(int u,int f,int op){
for(auto v : G[u]){
if(v == f)continue;
if(son[u] != v)dfs2(v,u,1); //处理轻儿子,消除影响
}
if(son[u])dfs2(son[u],u,0); //处理重儿子
cnt[col[u]]++;if(cnt[col[u]] == 1)now++;//加上当前点的贡献
for(auto v : G[u]){
if(v == f)continue;
if(son[u] != v)solve(v,u,1);//添加贡献
}
ans[u] = now; //更新答案
if(op == 1)solve(u,f,-1);//删除
}
int main(){
int n;cin >> n;
rep(i,1,n-1){
int u,v;cin >> u >> v;
G[u].pb(v);G[v].pb(u);
}
rep(i,1,n)cin >> col[i];
dfs(1,-1);
dfs2(1,-1,0);
int q;cin >> q;
while(q--){
int x;cin >> x;
cout << ans[x] << endl;
}
return 0;
}
CF600E Lomsat gelral
求子树中颜色最多的颜色权值之和,相同数量都要加上
#include
CF570D Tree Requests
a子树中深度为b的结点能否构成回文串
#include
CF246E Blood Cousins Return
a结点的k阶后代有多少个不同的值
#include
CF208E Blood Cousins
与a结点拥有共同k阶祖先的结点有多少个
(倍增找到a的k阶祖先,然后就是上一题CF246E了)
#include
CF1009F Dominant Indices
a子树中,找到层数结点数最多的那一层
#include
CF375D Tree and Queries
a子树中出现次数>=k的颜色有多少种
#include
https://codeforces.com/contest/291/problem/E、CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths、wannafly Day2 E 阔力梯的树
掌握套路!