[BZOJ 5072]小A的树
生活随笔
收集整理的這篇文章主要介紹了
[BZOJ 5072]小A的树
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Description
題庫鏈接
給你 \(n\) 個節點的一棵樹,點分黑白。 \(q\) 組詢問,每次詢問類似于“是否存在樹中 \(x\) 個點的連通塊恰有 \(y\) 個黑點”。 \(t\) 組數據。
\(1\leq t\leq 5,1\leq n\leq 5000,q\leq 10^5\)
Solution
由于詢問比較多,容易猜到一個結論,就是 \(x\) 個點的連通塊能取到黑點的個數一定是完整的一段區間。
就是只要 \(y\geq\) \(x\) 個點的連通塊黑點個數的下界,且 \(y\leq\) \(x\) 個點的連通塊黑點個數的上界,那么就滿足題設條件。
具體證明,大概就是在 \(x\) 個點的連通塊中刪去邊界一個點,再加上另一個不在連通塊內的點這樣黑點增量(減量)是不大于 \(1\) 的,那么就一定能取到一整段區間內的數。
可以用 \(O(n^2)\) 的樹上背包來預處理出這個上界下界。最后 \(O(1)\) 回答詢問即可。
Code
#include <bits/stdc++.h> using namespace std; const int N = 5000+5;int n, q, d[N], u, v, f[N][N], g[N][N], size[N]; struct tt {int to, next; }edge[N<<1]; int path[N], top;void dfs(int u, int fa) {if (d[u] == 1) f[u][1] = g[u][1] = 1;else f[u][1] = g[u][1] = 0;size[u] = 1; for (int i = path[u], v; ~i; i = edge[i].next)if ((v = edge[i].to) != fa) {dfs(v, u);for (int p = size[u]; p; p--)for (int q = size[v]; q; q--)f[u][p+q] = min(f[u][p+q], f[u][p]+f[v][q]),g[u][p+q] = max(g[u][p+q], g[u][p]+g[v][q]);size[u] += size[v];}for (int i = 1; i <= size[u]; i++)f[0][i] = min(f[0][i], f[u][i]), g[0][i] = max(g[0][i], g[u][i]); } void add(int u, int v) {edge[++top] = (tt){v, path[u]}; path[u] = top; } void work() {memset(path, top = -1, sizeof(path));scanf("%d%d", &n, &q);for (int i = 1; i < n; i++) scanf("%d%d", &u, &v), add(u, v), add(v, u);for (int i = 1; i <= n; i++) scanf("%d", &d[i]);memset(f, 127/3, sizeof(f)), memset(g, 0, sizeof(g));dfs(1, 0);while (q--) {scanf("%d%d", &u, &v);if (f[0][u] <= v && v <= g[0][u]) puts("YES");else puts("NO");}puts(""); } int main() {int t; cin >> t; while (t--) work(); return 0; }轉載于:https://www.cnblogs.com/NaVi-Awson/p/8980588.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的[BZOJ 5072]小A的树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Extjs grid 设置行字体颜色
- 下一篇: PAT1132: Cut Integer