• [CF768G] The Winds of Winter


    显然对于删去一个点之后形成的森林, 就是把最大的那棵树砍下来, 接到最小的树上.

    设删去当前点删去后形成的所有树中最大的那一棵大小为(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
    ", ans[i]);
    }
    
    int main() {
    	freopen("del.in", "r", stdin);
    	freopen("del.out", "w", stdout);
    
    	init();
    	solve();
    
    #ifdef Qrsikno
        debug("
    Running time: %.3lf(s)
    ", clock() * 1.0 / CLOCKS_PER_SEC);
    #endif
        return 0;
    }
    
    
    

  • 相关阅读:
    celery的使用
    MySQL的性能分析explain
    字典排序
    spark学习进度6——Scala中的List
    spark学习进度3——Scala方法与函数
    spark学习进度5——Scala中的数组
    spark学习进度4——Scala中的元组
    spark学习进度7——Scala中的Map集合
    我对vue3的理解
    vue2自定义指令加载指令vloading和占位图指令vshowimg
  • 原文地址:https://www.cnblogs.com/qrsikno/p/10325452.html
Copyright © 2020-2023  润新知