首页 > 其他分享 >cf321 C. Ciel the Commander

cf321 C. Ciel the Commander

时间:2022-08-25 12:26:51浏览次数:47  
标签:sz Ciel int cf321 dfs Commander fa ans mx

题意:

'A'~'Z'​ 给一棵树上的点染色,要求若两点字符相同则两点间的路径上一定有字符更小的点。

思路:

法一:点分治

树的重心能把树划分成每块大小不超过 \(n/2\) 的连通块

首先给整棵树的重心赋字符 A(显然整棵树中不能有两个 A),然后用 B~Z 处理去掉重心后的每个连通块。

\(log(1e5)<26\) 所以是够用的

const signed N = 5 + 1e5;
int n; vector<int> G[N];

bool vis[N]; int sz[N], res, root, tot; 
void getCentroid(int u, int fa) {
    sz[u] = 1; int mx = 0;
    for(int v : G[u]) if(v != fa && !vis[v]) {
        getCentroid(v, u);
        sz[u] += sz[v], mx = max(mx, sz[v]);
    }
    mx = max(mx, tot-sz[u]);
    if(mx < res) res = mx, root = u; 
}

char ans[N];
void dfs(int u, int fa) {
    res = INF, tot = tot ? sz[u] : n; //init
    getCentroid(u, fa), u = root, vis[u] = 1;

    ans[u] = fa ? ans[fa]+1 : 'A';

    for(int v : G[u]) if(v != fa && !vis[v])
        dfs(v, u);
}

void sol() {
    cin >> n; for(int i = 1; i < n; i++) {
        int x, y; cin >> x >> y;
        G[x].pb(y), G[y].pb(x);
    }

    dfs(1, 0);

    for(int i = 1; i <= n; i++) cout << ans[i] << ' ';
}

法二:从下往上模拟

对某点 \(u\),假设 \(u\) 的后代已经处理完毕,我们希望给 \(u\) 安排一个尽量大的字符

定义一个 \(u\) 的后代 \(v\) “暴露” 当且仅当从 \(v\) 到 \(u\) 的路径上没有比 \(v\) 小的点,那么 \(u\) 只需满足两个条件:

  1. \(u\) 不能与任何一个暴露点相等
  2. 若某字符 \(ch\) 对 \(u\) 的两个不同儿子来说都是暴露的,则 \(u\) 的字符须小于 \(ch\)

字符集很小,暴力检查即可。

树根随便取(比如取点1为根),一定有答案。不会证明...

const signed N = 5 + 1e5;
int n; vector<int> G[N];
int ans[N];
int dfs(int u, int fa) { //返回子树中暴露的字符集
    int Su = 0;
    vector<int> cnt(26);
    for(int v : G[u]) if(v != fa) {
        int Sv = dfs(v, u); Su |= Sv;
        for(int i = 0; i <= 25; i++)
            if(Sv>>i&1) cnt[i]++;
    }
    //处理在不同儿子子树中出现至少两次的字符
    ans[u] = 25; for(int i = 25; i; i--)
        if(cnt[i] >= 2) ans[u] = i - 1;
    //ans[u]不能等于任意暴露字符
    while(Su>>ans[u]&1) ans[u]--;

    return Su & ((1<<ans[u])-1) | (1<<ans[u]); //大于ans[u]的字符都不暴露
}

void sol() {
    cin >> n; for(int i = 1; i < n; i++) {
        int x, y; cin >> x >> y;
        G[x].pb(y), G[y].pb(x);
    }

    dfs(1, 0);

    for(int i = 1; i <= n; i++) cout << char(ans[i] + 'A') << ' ';
}

标签:sz,Ciel,int,cf321,dfs,Commander,fa,ans,mx
From: https://www.cnblogs.com/wushansinger/p/16623861.html

相关文章