• HDU 6241 Color a Tree


    Color a Tree

    题目大意:一棵树,根为1.某些点有一些限制。限制A: 该$x_i$点子树染色点至少$y_i$个。 限制B: 该$x_i$点子树外染色至少$y_i$个。求最少染色点数。

    首先是二分答案,二分染色的点数。check就是对于这个mid能否满足要求。

    令$f1[i]$表示$i$为根的子树的最少被染色个数。
    令$f2[i]$表示$i$为根的子树的最多被染色个数。

    符合要求的应该是$f1[i]<=mid<=f2[i]$。

    考虑到$[L,M]$与$[M+1,R]$这样的子树合并的时候要求和,考虑按dfs深度分化,或者bfs序。

    $f2[i]$更新由子树和mid-子树外的点的个数决定。
    $f2[i]=min(sum son,mid-bb[i])$.

    $f1[i]$更新由子树和和子树内的点限制。
    $f1[i]=max(sum son,aa[i])$.

    注意坑点 aa[i] 和 bb[i] 要取最大值。

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    const int maxn = 100005;
    vector<int> e[maxn];
    int fa[maxn];
    int Q[maxn], T, f, r;
    bool vis[maxn];
    int aa[maxn], bb[maxn], na, nb, u, v, n;
    int f1[maxn], f2[maxn], mid;
    
    bool dfs(int id, int fa) {
    	f1[id] = 0; f2[id] = 1;
    	bool ok = 1;
    	for (auto ep : e[id]) {
    		if (ep == fa) continue;
    		ok &= dfs(ep, id);
    		if (!ok) break;
    	}
    	if (!ok) return false;
    	if (bb[id] != -1) {
    		if (mid - bb[id] < f1[id]) return false;
    		f2[id] = min(f2[id], mid - bb[id]);
    	}
    	if (aa[id] != -1) {
    		if (f2[id] < aa[id]) return false;
    		f1[id]=max(f1[id],aa[id]);
    	}
    	f1[fa] += f1[id];
    	f2[fa] += f2[id];
    	return true;
    }
    
    bool check(int mid) {
    	f1[0] = f2[0] = 0;
    	bool ok = dfs(1, 0);
    	if (!ok) return false;
    	if (f1[0] > mid) return false;
    	if (f2[0] < mid) return false;
    	return true;
    }
    
    int main() {
    	//freopen("in.txt","r",stdin);
    	for (cin >> T; T--;) {
    		scanf("%d", &n);
    		memset(aa, -1, sizeof aa);
    		memset(bb, -1, sizeof bb);
    		for (int i = 1; i <= n; i++)
    			e[i].clear();
    		for (int i = 1; i < n; i++) {
    			scanf("%d%d", &u, &v);
    			e[u].push_back(v);
    			e[v].push_back(u);
    		}
    		scanf("%d", &na);
    		for (int i = 1; i <= na; i++) {
    			scanf("%d%d", &u, &v);
    			if (aa[u] == -1) aa[u] = v;
    			else aa[u] = max(aa[u], v);
    		}
    		scanf("%d", &nb);
    		for (int i = 1; i <= nb; i++) {
    			scanf("%d%d", &u, &v);
    			if (bb[u] == -1) bb[u] = v;
    			else bb[u] = max(bb[u], v);
    		}
    		int l = 1, r = n, res = -1;
    		while (l <= r) {
    			mid = (l + r) >> 1;
    			if (check(mid))
    				r = (res = mid) - 1;
    			else l = mid + 1;
    		}
    		printf("%d
    ", res);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Oracle 的日期类型
    简单的同步Socket程序服务端
    MMORPG中的相机跟随算法
    使用了UnityEditor中的API,打包时却不能打包UnityEditor的问题
    C# 中的关键字整理
    Unity3D C#中使用LINQ查询(与 SQL的区别)
    C# 值类型与引用类型的异同
    Unity3D NGUI事件监听的综合管理
    Unity3D 动画状态机简单控制核心代码
    Unity3D判断触摸方向
  • 原文地址:https://www.cnblogs.com/foreignbill/p/7841929.html
Copyright © 2020-2023  润新知