1. 程式人生 > >[CF768G] The Winds of Winter

[CF768G] The Winds of Winter

一個 暴力 erase else c++ pan 復雜 mes rep

顯然對於刪去一個點之後形成的森林, 就是把最大的那棵樹砍下來, 接到最小的樹上.

設刪去當前點刪去後形成的所有樹中最大的那一棵大小為\(Max\) , 最小的為Min, 次小值為Sec

設從最大樹砍掉的節點為u, 答案就是\(max\{Max - Size_u, Min + size_u, Sec\}\)

它關於\(Size_u\)變化的函數顯然是單峰的, 所以可以二分答案\(Ans\)一定要滿足\(Max - Size_u \leq Ans, Min + Size_u \leq Ans\)

就是: \(Max - Ans \leq Siz_u \leq Ans - Min\) , 只要找是否存在這樣的點即可

這樣處理的時候就很像DSU on tree, 每次暴力把輕兒子的貢獻加入整體, 重兒子直接繼承, 然後清空輕兒子的貢獻.

討論的時候要註意分三類討論, 分成兩大類, 分別是去掉這個點有無影響, 然後無影響又分為子樹和其他部分.

時間復雜度是\(O(n log^2 n log V)\)? 不知道為什麽跑這麽快


二分答案其實就是一個放寬答案取值區間的操作, 因為二分答案的時候保證了單調性, 所以可以直接計算考慮函數在定義域內的極值, 那麽就轉換成了最大/最小問題, 這也是他所以直接跟貪心相關.

那麽就自然要求統計樹上信息, 因為沒有修改, 所以直接DSU on tree,

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)
#define clar(a, b) memset((a), (b), sizeof(a))
#define debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
int read() {
    char ch = getchar();
    int x = 0, flag = 1;
    for (;!isdigit(ch); ch = getchar()) if (ch == ‘-‘) flag *= -1;
    for (;isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    return x * flag;
}
void write(int x) {
    if (x < 0) putchar(‘-‘), x = -x;
    if (x >= 10) write(x / 10);
    putchar(x % 10 + 48);
}

const int Maxn = 500009;
struct edge {
    int to, nxt;
}g[Maxn << 1];
int n, fa[Maxn], head[Maxn], e, rt = 0;
int ans[Maxn];

void add(int u, int v) {
    g[++e] = (edge){v, head[u]}, head[u] = e;
}

int size[Maxn], son[Maxn]; 

int val[Maxn];

multiset <int> Ots, ancestor, Self[Maxn];

void dfsInit(int u) {
    size[u] = 1;            
    for (int i = head[u]; ~i; i = g[i].nxt) {
        int v = g[i].to;
        if (v != fa[u]) {
            dfsInit(v);
            if (size[v] > size[son[u]]) son[u] = v;
            size[u] += size[v];
        }
    }
    if (u != rt) Ots.insert(size[u]);
}
void init() {
    clar(head, -1);
    n = read();
    rep (i, 1, n) {
        int u = read(), v = read();
        fa[v] = u; add(v, u); add(u, v);
        if (!u) rt = v;
    }

    dfsInit(1);
}

bool check(int opt, int val, int u, int Min, int Max) {
    if (opt == 1) {
        multiset <int> :: iterator IT = Self[son[u]].lower_bound(Max - val);
        if (IT != Self[son[u]].end() && (*IT) <= val - Min) return true;
    } else {
        multiset <int> :: iterator IT = Ots.lower_bound(Max - val);
        if (IT != Ots.end() && (*IT) <= val - Min) return true;

        IT = ancestor.lower_bound(Max - val + size[u]);
        if (IT != ancestor.end() && (*IT) <= val - Min + size[u]) return true;
    }
    return 0;
}

void dfs(int u) {
    if (u != rt) Ots.erase(Ots.find(size[u]));
    if (fa[u] && fa[u] != rt) ancestor.insert(size[fa[u]]); 
    int Fisr = max(n - size[u], size[son[u]]), Seco = min(n - size[u], size[son[u]]), Min = n - size[u];
    if (!Min) Min = size[son[u]];

    for (int i = head[u]; ~i; i = g[i].nxt) {
        int v = g[i].to;
        if (v != fa[u] && v != son[u]) {
            dfs(v);
            for (multiset <int> :: iterator IT = Self[v].begin(); IT != Self[v].end(); ++IT) 
                Ots.insert(*IT);
            Min = min(Min, size[v]); Seco = max(Seco, size[v]);
        }
    }
    if (son[u]) dfs(son[u]), Min = min(Min, size[son[u]]);

    for (int i = head[u]; ~i; i = g[i].nxt) {
        int v = g[i].to;
        if (v != fa[u] && v != son[u]) 
            for (multiset <int> :: iterator IT = Self[v].begin(); IT != Self[v].end(); ++IT) 
                Ots.erase(Ots.find(*IT));
    }

    if (Seco != Fisr) {
        int l = Seco, r = Fisr, opt = (Fisr == size[son[u]]);
        while (l <= r) {
            int mid = (l + r) >> 1;
            if (check(opt, mid, u, Min, Fisr)) ans[u] = mid, r = mid - 1;
            else l = mid + 1;
        }
    }

    if (!ans[u]) ans[u] = Fisr;
    if (son[u]) swap(Self[son[u]], Self[u]);

    for (int i = head[u]; ~i; i = g[i].nxt) {
        int v = g[i].to;
        if (v != fa[u] && v != son[u]) 
            for (multiset <int> :: iterator IT = Self[v].begin(); IT != Self[v].end(); Self[v].erase(IT++)) Self[u].insert(*IT);
    }

    if (fa[u] && fa[u] != rt) ancestor.erase(ancestor.find(size[fa[u]])); 
    Self[u].insert(size[u]);
}

void solve() {
    dfs(rt);
    rep (i, 1, n) printf("%d\n", ans[i]);
}

int main() {
    freopen("del.in", "r", stdin);
    freopen("del.out", "w", stdout);

    init();
    solve();

#ifdef Qrsikno
    debug("\nRunning time: %.3lf(s)\n", clock() * 1.0 / CLOCKS_PER_SEC);
#endif
    return 0;
}

?

[CF768G] The Winds of Winter