dsu on tree 练习题

参考链接:https://blog.csdn.net/qq_43472263/article/details/104150940

U41492 树上数颜色 https://www.luogu.com.cn/problem/U41492

求子树的颜色数有多少种

/*
U41492 树上数颜色
计算v的子树中颜色有多少种
*/
#include<bits/stdc++.h>
#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;
}
View Code

CF600E Lomsat gelral

求子树中颜色最多的颜色权值之和,相同数量都要加上

#include<map>
#include<set>
#include<cmath>
#include<deque>
#include<queue>
#include<stack>
#include<string>
#include<bitset>
#include<cstdio>
#include<vector>
#include<complex>
#include<iomanip>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
#include<unordered_map>
//#include<bits/stdc++.h>
#define fi first
#define se second
#define eps 1e-8
#define ll long long
#define ull unsigned long long
#define pb push_back
//#define N 101000
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define P pair<double, ll>
#define pi acos(-1)
#define lson l,mid,rt*2
#define rson mid+1,r,rt*2+1
#define lowbit(x) (x&(-x))
#define SZ(x) ((ll)(x).size())
#define met(a,x) memset(a,x,sizeof(a))
#define openin(x) freopen(x, "r", stdin)
#define openout(x) freopen(x, "w",stdout)
#define rep(i,a,b) for(ll i = a;i <= b;i++)
#define bep(i,a,b) for(ll i = a;i >= b;i--)
#define ios() ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
ll mod = 1e9+7;
ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
ll lcm(ll a, ll b) { return a * b / gcd(a, b); }
int days[15] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int is_leapyear(int y) {
    return y % 400 == 0 || (y % 4 == 0 && y % 100 != 0);
}
int dx[8] = {0,0,1,-1,-1,-1,1,1};
int dy[8] = {1,-1,0,0,-1,1,-1,1};
inline ll read() {
    ll x = 0, sign = 1; char ch = getchar();
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') sign = -1;
    for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
    return sign * x;
}
inline void write(ll x){
    char r[30];
    int t = 0;
    if(x < 0){
        x = -x;
        putchar('-');
    }
    do{
        r[t++] = x % 10 + '0';
        x /= 10;
    }while(x);
    while(t)putchar(r[--t]);
}
inline void writesp(ll x){
    write(x);
    putchar(' ');
}
inline void writeln(ll x){
    write(x);
    putchar('
');
}
inline void writedo(double x,int op){
    cout << fixed <<setprecision(op) << x << endl;
}
ll qpow(ll a, ll b) {
    ll ans = 1;
    while (b) {
        if (b & 1)ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}
const int N = 100010;
int sz[N],son[N];//字树大小、重儿子编号
ll col[N],ans[N],now,cnt[N],mx;
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){
    cnt[col[u]] += op;
    if(op == 1){
        if(cnt[col[u]] > mx){
            mx = cnt[col[u]];
            now = col[u];
        }
        else if(cnt[col[u]] == mx){
            now += col[u];
        }
    }
    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]] > mx){
        mx = cnt[col[u]];
        now = col[u];
    }
    else if(cnt[col[u]] == mx){
        now += 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),now=0,mx = 0;//删除
}
int main(){
    int n;cin >> n;
    rep(i,1,n)cin >> col[i];
    rep(i,1,n-1){
        int u,v;cin >> u >> v;
        G[u].pb(v);G[v].pb(u);
    }
    dfs(1,-1);
    dfs2(1,-1,0);
    rep(i,1,n)cout << ans[i] << ' ';
    cout << endl;
    return 0;
}
View Code

CF570D Tree Requests

a子树中深度为b的结点能否构成回文串

#include<map>
#include<set>
#include<cmath>
#include<deque>
#include<queue>
#include<stack>
#include<string>
#include<bitset>
#include<cstdio>
#include<vector>
#include<complex>
#include<iomanip>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
#include<unordered_map>
//#include<bits/stdc++.h>
#define fi first
#define se second
#define eps 1e-8
#define ll long long
#define ull unsigned long long
#define pb push_back
//#define N 101000
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define P pair<ll, ll>
#define pi acos(-1)
#define lson l,mid,rt*2
#define rson mid+1,r,rt*2+1
#define lowbit(x) (x&(-x))
#define SZ(x) ((ll)(x).size())
#define met(a,x) memset(a,x,sizeof(a))
#define openin(x) freopen(x, "r", stdin)
#define openout(x) freopen(x, "w",stdout)
#define rep(i,a,b) for(ll i = a;i <= b;i++)
#define bep(i,a,b) for(ll i = a;i >= b;i--)
#define ios() ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
ll mod = 1e9+7;
ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
ll lcm(ll a, ll b) { return a * b / gcd(a, b); }
int days[15] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int is_leapyear(int y) {
    return y % 400 == 0 || (y % 4 == 0 && y % 100 != 0);
}
int dx[8] = {0,0,1,-1,-1,-1,1,1};
int dy[8] = {1,-1,0,0,-1,1,-1,1};
inline ll read() {
    ll x = 0, sign = 1; char ch = getchar();
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') sign = -1;
    for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
    return sign * x;
}
inline void write(ll x){
    char r[30];
    int t = 0;
    if(x < 0){
        x = -x;
        putchar('-');
    }
    do{
        r[t++] = x % 10 + '0';
        x /= 10;
    }while(x);
    while(t)putchar(r[--t]);
}
inline void writesp(ll x){
    write(x);
    putchar(' ');
}
inline void writeln(ll x){
    write(x);
    putchar('
');
}
inline void writedo(double x,int op){
    cout << fixed <<setprecision(op) << x << endl;
}
ll qpow(ll a, ll b) {
    ll ans = 1;
    while (b) {
        if (b & 1)ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}
const int N = 500010;
int sz[N],son[N];//字树大小、重儿子编号
ll bit[N],ans[N],dep[N];
int SON;
vector<int>G[N];
vector<P>vec[N];
char s[N];
void dfs(int u,int f){ //找重儿子
    sz[u] = 1;
    if(f != -1)dep[u] = dep[f] + 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){
    bit[dep[u]] ^= (1ll << (s[u-1]-'a'));
    for(auto v : G[u]){
        if(v == f)continue;
        if(v != SON)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),SON = son[u]; //处理重儿子
    solve(u,f,op);
    for(auto v : vec[u]){
        int cnt = __builtin_popcount(bit[v.second-1]);
        if(cnt <= 1)ans[v.first] = 1;
    }
    SON = 0;
    if(op == 1)solve(u,f,-1);//删除
}
int main(){
//    cout << __builtin_popcount(1);//二进制中有多少个1
    int n,q;cin >> n >> q;
//    rep(i,1,n)cin >> col[i];
    rep(i,2,n){
        int x = read();
        G[x].pb(i);
    }
    scanf("%s",&s);
    rep(i,1,q){
        int x = read(),y = read();
        vec[x].pb(P(i,y));
    }
    dfs(1,-1);
    dfs2(1,-1,1);
    rep(i,1,q){
        if(ans[i])puts("Yes");
        else puts("No");
    }
    return 0;
}
View Code

CF246E Blood Cousins Return

a结点的k阶后代有多少个不同的值

#include<map>
#include<set>
#include<cmath>
#include<deque>
#include<queue>
#include<stack>
#include<string>
#include<bitset>
#include<cstdio>
#include<vector>
#include<complex>
#include<iomanip>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
#include<unordered_map>
//#include<bits/stdc++.h>
#define fi first
#define se second
#define eps 1e-8
#define ll long long
#define ull unsigned long long
#define pb push_back
//#define N 101000
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define P pair<ll, ll>
#define pi acos(-1)
#define lson l,mid,rt*2
#define rson mid+1,r,rt*2+1
#define lowbit(x) (x&(-x))
#define SZ(x) ((ll)(x).size())
#define met(a,x) memset(a,x,sizeof(a))
#define openin(x) freopen(x, "r", stdin)
#define openout(x) freopen(x, "w",stdout)
#define rep(i,a,b) for(ll i = a;i <= b;i++)
#define bep(i,a,b) for(ll i = a;i >= b;i--)
#define ios() ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
ll mod = 1e9+7;
ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
ll lcm(ll a, ll b) { return a * b / gcd(a, b); }
int days[15] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int is_leapyear(int y) {
    return y % 400 == 0 || (y % 4 == 0 && y % 100 != 0);
}
int dx[8] = {0,0,1,-1,-1,-1,1,1};
int dy[8] = {1,-1,0,0,-1,1,-1,1};
inline ll read() {
    ll x = 0, sign = 1; char ch = getchar();
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') sign = -1;
    for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
    return sign * x;
}
inline void write(ll x){
    char r[30];
    int t = 0;
    if(x < 0){
        x = -x;
        putchar('-');
    }
    do{
        r[t++] = x % 10 + '0';
        x /= 10;
    }while(x);
    while(t)putchar(r[--t]);
}
inline void writesp(ll x){
    write(x);
    putchar(' ');
}
inline void writeln(ll x){
    write(x);
    putchar('
');
}
inline void writedo(double x,int op){
    cout << fixed <<setprecision(op) << x << endl;
}
ll qpow(ll a, ll b) {
    ll ans = 1;
    while (b) {
        if (b & 1)ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}
const int N = 500010;
int sz[N],son[N];//字树大小、重儿子编号
int ans[N],dep[N];
int val[N];
bitset<N>bit;
vector<int>G[N];
vector<P>vec[N];
set<int>sta[N];
multiset<int>sta2[N];
void dfs(int u,int f){ //找重儿子
    sz[u] = 1;
    if(f != -1)dep[u] = dep[f] + 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){

    if(op == 1) {
        sta[dep[u]].insert(val[u]);
//        sta2[dep[u]].insert(val[u]);
    }
    else {
        sta[dep[u]].erase(val[u]);
//        sta2[dep[u]].erase(sta2[dep[u]].find(val[u]));
//        if(sta2[dep[u]].find(val[u]) == sta2[dep[u]].end()){
//            sta[dep[u]].erase(val[u]);
//        }
    }
    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); //处理重儿子
    sta[dep[u]].insert(val[u]);
//    sta2[dep[u]].insert(val[u]);
    for(auto v : G[u]){
        if(son[u] != v)solve(v,u,1);
    }
    for(auto v : vec[u]){
        ans[v.first] = SZ(sta[dep[u] + v.second]);
    }
    if(op == 1)solve(u,f,-1);//删除
}
map<string,int>mp;
int tot;
vector<int>v;
int main(){
//    cout << __builtin_popcount(b);//二进制中有多少个1
    int n = read();
    rep(i,1,n){
        string str;
        int pa;
        cin >> str >> pa;
        if(!mp.count(str))mp[str] = ++tot;
        val[i] = mp[str];
        if(pa == 0)v.pb(i);
        else G[pa].pb(i);
    }
//    rep(i,1,n){
//        cout << val[i] << ' ';
//    }
//    cout << endl;
    int q = read();
    rep(i,1,q){
        int x = read(),y = read();
        vec[x].pb(P(i,y));
    }
    for(auto root : v){
        dfs(root,-1);
        dfs2(root,-1,1);
    }
    rep(i,1,q) writeln(ans[i]);
    return 0;
}
View Code

CF208E Blood Cousins

与a结点拥有共同k阶祖先的结点有多少个

(倍增找到a的k阶祖先,然后就是上一题CF246E了)

#include<map>
#include<set>
#include<cmath>
#include<deque>
#include<queue>
#include<stack>
#include<string>
#include<bitset>
#include<cstdio>
#include<vector>
#include<complex>
#include<iomanip>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
#include<unordered_map>
//#include<bits/stdc++.h>
#define fi first
#define se second
#define eps 1e-8
#define ll long long
#define ull unsigned long long
#define pb push_back
//#define N 101000
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define P pair<ll, ll>
#define pi acos(-1)
#define lson l,mid,rt*2
#define rson mid+1,r,rt*2+1
#define lowbit(x) (x&(-x))
#define SZ(x) ((ll)(x).size())
#define met(a,x) memset(a,x,sizeof(a))
#define openin(x) freopen(x, "r", stdin)
#define openout(x) freopen(x, "w",stdout)
#define rep(i,a,b) for(ll i = a;i <= b;i++)
#define bep(i,a,b) for(ll i = a;i >= b;i--)
#define ios() ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
ll mod = 1e9+7;
ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
ll lcm(ll a, ll b) { return a * b / gcd(a, b); }
int days[15] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int is_leapyear(int y) {
    return y % 400 == 0 || (y % 4 == 0 && y % 100 != 0);
}
int dx[8] = {0,0,1,-1,-1,-1,1,1};
int dy[8] = {1,-1,0,0,-1,1,-1,1};
inline ll read() {
    ll x = 0, sign = 1; char ch = getchar();
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') sign = -1;
    for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
    return sign * x;
}
inline void write(ll x){
    char r[30];
    int t = 0;
    if(x < 0){
        x = -x;
        putchar('-');
    }
    do{
        r[t++] = x % 10 + '0';
        x /= 10;
    }while(x);
    while(t)putchar(r[--t]);
}
inline void writesp(ll x){
    write(x);
    putchar(' ');
}
inline void writeln(ll x){
    write(x);
    putchar('
');
}
inline void writedo(double x,int op){
    cout << fixed <<setprecision(op) << x << endl;
}
ll qpow(ll a, ll b) {
    ll ans = 1;
    while (b) {
        if (b & 1)ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}
const int N = 100010;
int sz[N],son[N];//字树大小、重儿子编号
int ans[N],dep[N];
int val[N];
int pa[N][21];
vector<int>G[N];
vector<P>vec[N];
set<int>sta[N];
void dfs(int u,int f){ //找重儿子
    pa[u][0] = f;
    sz[u] = 1;
    if(f != -1)dep[u] = dep[f] + 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){

    if(op == 1) {
        sta[dep[u]].insert(val[u]);
    }
    else {
        sta[dep[u]].erase(val[u]);
    }
    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); //处理重儿子
    sta[dep[u]].insert(val[u]);
    for(auto v : G[u]){
        if(son[u] != v)solve(v,u,1);
    }
    for(auto v : vec[u]){
        ans[v.first] = SZ(sta[dep[v.second]]) - 1;
    }
    if(op == 1)solve(u,f,-1);//删除
}
int tot;
vector<int>v;
int Find(int x,int y){ //x的y阶级祖先
    int pos = 0;
    while(y){
        if(y & 1)x = pa[x][pos];
        if(x == -1)return -1;
        y >>= 1;
        pos++;
    }
    return x;
}
int main(){
//    cout << __builtin_popcount(b);//二进制中有多少个1
    int n = read();
    rep(i,1,n){
        val[i] = i;
        int pa;
        cin >> pa;
        if(pa == 0)v.pb(i);
        else G[pa].pb(i);
    }
    for(auto root : v){
        dfs(root,-1);
    }
    for(int i = 1;i <= n;i++){
        for(int j = 1;j <= 20;j++){
            if(pa[i][j-1] != -1) pa[i][j] = pa[pa[i][j-1]][j-1];
            else pa[i][j] = -1;
        }
    }
    int q = read();
    rep(i,1,q){
        int x = read(),y = read();
        int z = Find(x,y);
        if(z >= 1) vec[z].pb(P(i,x));
//        cout << z << ' ' << i << ' ' << x << endl;
    }
    for(auto root : v){
        dfs2(root,-1,1);
    }
    rep(i,1,q) writeln(ans[i]);
    return 0;
}
View Code

CF1009F Dominant Indices

a子树中,找到层数结点数最多的那一层

#include<map>
#include<set>
#include<cmath>
#include<deque>
#include<queue>
#include<stack>
#include<string>
#include<bitset>
#include<cstdio>
#include<vector>
#include<complex>
#include<iomanip>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
#include<unordered_map>
//#include<bits/stdc++.h>
#define fi first
#define se second
#define eps 1e-8
#define ll long long
#define ull unsigned long long
#define pb push_back
//#define N 101000
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define P pair<ll, ll>
#define pi acos(-1)
#define lson l,mid,rt*2
#define rson mid+1,r,rt*2+1
#define lowbit(x) (x&(-x))
#define SZ(x) ((ll)(x).size())
#define met(a,x) memset(a,x,sizeof(a))
#define openin(x) freopen(x, "r", stdin)
#define openout(x) freopen(x, "w",stdout)
#define rep(i,a,b) for(ll i = a;i <= b;i++)
#define bep(i,a,b) for(ll i = a;i >= b;i--)
#define ios() ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
ll mod = 1e9+7;
ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
ll lcm(ll a, ll b) { return a * b / gcd(a, b); }
int days[15] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int is_leapyear(int y) {
    return y % 400 == 0 || (y % 4 == 0 && y % 100 != 0);
}
int dx[8] = {0,0,1,-1,-1,-1,1,1};
int dy[8] = {1,-1,0,0,-1,1,-1,1};
inline ll read() {
    ll x = 0, sign = 1; char ch = getchar();
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') sign = -1;
    for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
    return sign * x;
}
inline void write(ll x){
    char r[30];
    int t = 0;
    if(x < 0){
        x = -x;
        putchar('-');
    }
    do{
        r[t++] = x % 10 + '0';
        x /= 10;
    }while(x);
    while(t)putchar(r[--t]);
}
inline void writesp(ll x){
    write(x);
    putchar(' ');
}
inline void writeln(ll x){
    write(x);
    putchar('
');
}
inline void writedo(double x,int op){
    cout << fixed <<setprecision(op) << x << endl;
}
ll qpow(ll a, ll b) {
    ll ans = 1;
    while (b) {
        if (b & 1)ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}
const int N = 1000010;
int sz[N],son[N];//字树大小、重儿子编号
int ans[N],dep[N],cnt[N],mx,res,mxid;
int val[N],last;
vector<int>G[N];
void dfs(int u,int f){ //找重儿子
    sz[u] = 1;
    if(f != -1)dep[u] = dep[f] + 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){
    cnt[dep[u]] += op;
    if(op == 1 && cnt[dep[u]] >= mx){
        if(cnt[dep[u]] > mx){
            mxid = u;
            mx = cnt[dep[u]];
        }
        else if(cnt[dep[u]] == mx){
            if(dep[u] < dep[mxid]){
                mxid = u;
            }
        }
    }
    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[dep[u]]++;
    if(cnt[dep[u]] >= mx){
        if(cnt[dep[u]] > mx){
            mx = cnt[dep[u]];
            mxid = u;
        }
        else if(cnt[dep[u]] == mx){
            if(dep[u] < dep[mxid]){
                mxid = u;
            }
        }
        res = 0;
    }
    last = u;
    for(auto v : G[u]){
        if(v == f)continue;
        if(son[u] != v)solve(v,u,1);
    }
    if(mxid)res = dep[mxid] - dep[u];
    ans[u] = res;
//    cout << u << ' ' << mx << ' ' << res << endl;
    if(op == 1)solve(u,f,-1),res = 0,mx = 0,mxid = 0;//删除
}

int main(){
    int n = read();
    rep(i,1,n-1){
        int u = read(),v = read();
        G[u].pb(v);G[v].pb(u);
    }
    int root = 1;
    dfs(root,-1);
//    rep(i,1,n)cout << dep[i] << ' ';
//    cout << endl;
    dfs2(root,-1,1);
    rep(i,1,n) writeln(ans[i]);
    return 0;
}
View Code

CF375D Tree and Queries

a子树中出现次数>=k的颜色有多少种

#include<map>
#include<set>
#include<cmath>
#include<deque>
#include<queue>
#include<stack>
#include<string>
#include<bitset>
#include<cstdio>
#include<vector>
#include<complex>
#include<iomanip>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
#include<unordered_map>
//#include<bits/stdc++.h>
#define fi first
#define se second
#define eps 1e-8
#define ll long long
#define ull unsigned long long
#define pb push_back
//#define N 101000
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define P pair<ll, ll>
#define pi acos(-1)
#define lson l,mid,rt*2
#define rson mid+1,r,rt*2+1
#define lowbit(x) (x&(-x))
#define SZ(x) ((ll)(x).size())
#define met(a,x) memset(a,x,sizeof(a))
#define openin(x) freopen(x, "r", stdin)
#define openout(x) freopen(x, "w",stdout)
#define rep(i,a,b) for(ll i = a;i <= b;i++)
#define bep(i,a,b) for(ll i = a;i >= b;i--)
#define ios() ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
ll mod = 1e9+7;
ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
ll lcm(ll a, ll b) { return a * b / gcd(a, b); }
int days[15] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int is_leapyear(int y) {
    return y % 400 == 0 || (y % 4 == 0 && y % 100 != 0);
}
int dx[8] = {0,0,1,-1,-1,-1,1,1};
int dy[8] = {1,-1,0,0,-1,1,-1,1};
inline ll read() {
    ll x = 0, sign = 1; char ch = getchar();
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') sign = -1;
    for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
    return sign * x;
}
inline void write(ll x){
    char r[30];
    int t = 0;
    if(x < 0){
        x = -x;
        putchar('-');
    }
    do{
        r[t++] = x % 10 + '0';
        x /= 10;
    }while(x);
    while(t)putchar(r[--t]);
}
inline void writesp(ll x){
    write(x);
    putchar(' ');
}
inline void writeln(ll x){
    write(x);
    putchar('
');
}
inline void writedo(double x,int op){
    cout << fixed <<setprecision(op) << x << endl;
}
ll qpow(ll a, ll b) {
    ll ans = 1;
    while (b) {
        if (b & 1)ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}
const int N = 100010;
int sz[N],son[N];//字树大小、重儿子编号
int ans[N],dep[N],cnt[N],num[N];//答案、深度、cnt[i]代表i颜色出现多少次,num[i]代表出现次数>=i的有多少个
int col[N];//i点的颜色
vector<int>G[N];
vector<P>vec[N];
void dfs(int u,int f){ //找重儿子
    sz[u] = 1;
    if(f != -1)dep[u] = dep[f] + 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){
    if(op == -1){
        num[cnt[col[u]]] -= 1;
        cnt[col[u]] -= 1;
    }
    if(op == 1){
        cnt[col[u]] += 1;
        num[cnt[col[u]]] += 1;
    }
    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]]++;//col[u]出现次数+1
    num[cnt[col[u]]]++;//出现cnt[col[u]]次,次数+1
    for(auto v : G[u]){
        if(v == f)continue;
        if(son[u] != v)solve(v,u,1);
    }
    for(auto v : vec[u]){
        ans[v.first] = num[v.second];
    }
    if(op == 1)solve(u,f,-1);//删除
}

int main(){
    int n = read(),q = read();
    rep(i,1,n)col[i] = read();
    rep(i,1,n-1){
        int u = read(),v = read();
        G[u].pb(v);G[v].pb(u);
    }
    rep(i,1,q){
        int x = read(),y = read();
        vec[x].pb(P(i,y));
    }
    int root = 1;
    dfs(root,-1);
    dfs2(root,-1,1);
    rep(i,1,q) writeln(ans[i]);
    return 0;
}
View Code

https://codeforces.com/contest/291/problem/ECF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh pathswannafly Day2 E 阔力梯的树

掌握套路!

原文地址:https://www.cnblogs.com/cherish-lin/p/13788579.html