CodeForces - 708C Centroids

题意:

给定一棵有 n n 个结点的树,问对于每个点 u u ,是否有可能通过移动至多一条边使得原图仍为一棵树并且 u u 为树的重心。 ( n 4 × 1 0 5 ) (n \leq 4 × 10^5)

链接:

https://codeforces.com/problemset/problem/708/C

解题思路:

考虑 u u 能成为重心的情况,找到其重儿子 v v ,若重儿子子树大小不超过 n 2 \frac{n}{2} ,则可成为重心,否则必须进一步考虑。考虑从重儿子子树里移除一部分直接拼接到 u u ,这一部分大小必须为 [ s i z [ v ] n 2 , n 2 ] [siz[v] - \frac{n}{2},\frac{n}{2}] ,即查找 v v 子树中是否存在子树大小在此区间范围。
 
1 1 号结点为根考虑求解,讨论 u u 的重儿子取向。若 u u 的重儿子不是父结点方向,这一部分的 u u 可以通过主席树或 d s u   o n   t r e e dsu~on~tree 求解。若 u u 的重儿子往父结点方向,则查询区间变成 u u 的外部,且从 1 1 号结点到 u u 路径上的结点的子树大小相对于 u u 来讲有所变化,静态主席树不支持更新,故用 d s u   o n   t r e e dsu~on~tree 沿途修改即可。
 
简化做法:先找到重心 r t rt ,以它为根考虑其他结点的求解。重心为根,则其他结点的重儿子只可能是父结点方向,并且移除子树的情况只有两种:① 移除 r t rt 往该结点 u u 方向上的这条边;② 移除 r t rt 子树内最大的一棵(不大于 n 2 \frac{n}{2} )。讨论然后 d f s dfs 即可。

参考代码:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define sz(a) ((int)a.size())
#define pb push_back
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 4e5 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

vector<int> G[maxn];
int siz[maxn], son[maxn], mx[maxn], fa[maxn];
int up[maxn], c[maxn], vis[maxn], ans[maxn];
int n;

#define lowb(x) ((x)&(-x))
void update(int x, int val){

    while(x <= n) c[x] += val, x += lowb(x);
}

int query(int x){

    int ret = 0;
    while(x > 0) ret += c[x], x -= lowb(x);
    return ret;
}

void dfs1(int u, int f){

    siz[u] = 1, son[u] = 0, mx[u] = 0, fa[u] = f;
    for(auto &v : G[u]){

        if(v == f) continue;
        dfs1(v, u);
        siz[u] += siz[v];
        mx[u] = max(mx[u], siz[v]);
        if(siz[v] > siz[son[u]]) son[u] = v;
    }
    mx[u] = max(mx[u], n - siz[u]);
    if(n - siz[u] > siz[son[u]]) up[u] = 1;
    update(siz[u], 1);
}

void add(int u, int f, int val){

    update(siz[u], val);
    for(auto &v : G[u]){

        if(v == f || vis[v]) continue;
        add(v, u, val);
    }
}

void judge(int u){

    int l = mx[u] - n / 2, r = n / 2;
    int tmp = query(r) - query(l - 1);
    // cout << u << " " << ans[u] << " " << l << " " << r << endl;
    ans[u] = tmp > 0;
}

void dfs2(int u, int f, int flg){

    // cout << u << " ? " << f << " " << flg << endl;
    for(auto &v : G[u]){

        if(v == f || v == son[u]) continue;
        int nsz = n - siz[v];
        update(siz[u], -1), update(nsz, 1);
        dfs2(v, u, 0);
        update(siz[u], 1), update(nsz, -1);
    }
    if(son[u]){

        int nsz = n - siz[son[u]];
        update(siz[u], -1), update(nsz, 1);
        dfs2(son[u], u, 1), vis[son[u]] = 1;
        update(siz[u], 1), update(nsz, -1);
    }
    add(u, f, -1);
    if(up[u]) judge(u);
    if(son[u]) vis[son[u]] = 0;
    if(!flg) add(u, f, 1);
}

void dfs3(int u, int f, int flg){

    for(auto &v : G[u]){

        if(v == f || v == son[u]) continue;
        dfs3(v, u, 0);
    }
    if(son[u]) dfs3(son[u], u, 1), vis[son[u]] = 1;
    if(!up[u]) judge(u);
    add(u, f, 1);
    if(son[u]) vis[son[u]] = 0;
    if(!flg) add(u, f, -1);
}

int main(){

    ios::sync_with_stdio(0); cin.tie(0);
    cin >> n;
    for(int i = 1; i < n; ++i){

        int u, v; cin >> u >> v;
        G[u].pb(v), G[v].pb(u);
    }
    dfs1(1, 0);
    dfs2(1, 0, 0);
    for(int i = 1; i <= n; ++i) c[i] = 0;
    dfs3(1, 0, 0);
    for(int i = 1; i <= n; ++i) cout << ans[i] << " "; cout << endl;
    return 0;
}

 
智力打击:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define sz(a) ((int)a.size())
#define pb push_back
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 4e5 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

vector<int> G[maxn];
int siz[maxn], rmx[maxn], ans[maxn];
int n, rmn, rt, mx, mx2;

void dfs1(int u, int f){

    rmx[u] = 0, siz[u] = 1;
    for(auto &v : G[u]){

        if(v == f) continue;
        dfs1(v, u);
        siz[u] += siz[v];
        rmx[u] = max(rmx[u], siz[v]);
    }
    rmx[u] = max(rmx[u], n - siz[u]);
    if(rmx[u] < rmn) rmn = rmx[u], rt = u;
}

void dfs2(int u, int f, int mx){

    if(rmx[u] > n / 2) {
        
        ans[u] = rmx[u] - mx <= n / 2;
    }
    else ans[u] = 1;
    for(auto &v : G[u]){

        if(v == f) continue;
        dfs2(v, u, mx);
    }
}

int main(){

    ios::sync_with_stdio(0); cin.tie(0);
    cin >> n;
    for(int i = 1; i < n; ++i){

        int u, v; cin >> u >> v;
        G[u].pb(v), G[v].pb(u);
    }
    rmn = inf, dfs1(1, 0);
    rmn = 0, dfs1(rt, 0);
    for(auto &v : G[rt]){

        if(siz[v] > mx) mx2 = mx, mx = siz[v];
        else if(siz[v] > mx2) mx2 = siz[v];
    }
    ans[rt] = 1;
    // cout << rt << endl;
    for(auto &v : G[rt]){

        int tmp = siz[v] == mx ? mx2 : mx;
        if(n - siz[v] <= n / 2) tmp = n - siz[v];
        dfs2(v, rt, tmp);
    }
    for(int i = 1; i <= n; ++i) cout << ans[i] << " "; cout << endl;
    return 0;
}
发布了55 篇原创文章 · 获赞 0 · 访问量 1239

猜你喜欢

转载自blog.csdn.net/weixin_44059127/article/details/104091661
今日推荐