HDU 6241 Color a Tree
Color a Tree
题目大意:一棵树,根为1.某些点有一些限制。限制A: 该xi点子树染色点至少yi个。 限制B: 该xi点子树外染色至少yi个。求最少染色点数。
首先是二分答案,二分染色的点数。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(∑son,mid−bb[i]).
f1[i]更新由子树和和子树内的点限制。
f1[i]=max(∑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\n", res);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步