【GDOI2018模拟9.23】博弈

来源:互联网 发布:按照文件夹恢复数据 编辑:程序博客网 时间:2024/05/20 12:48

Description:

这里写图片描述
1<=n<=10^6

题解:

首先策略肯定是把Tom逼到一个点,然后去删边,接着取消标记让Tom一步步走到T那儿去。
Tom肯定会往代价最大的地方钻,1/4可以选择封住最大的先,然后Tom往次大的走。
以b为根,建树。
对于不在b->t的路径上的点,求出w,表示往它的子树中走一圈回来的最小代价,dp显然。
现在你可以想像从b->t走,你可以删掉相邻的子树,但是你不知道删哪棵。
于是二分答案,遵循能删必删的思想,就可以确定了,直到某个深度不行了。

Code:

#include<cstdio>#include<cstring>#include<algorithm>#define fo(i, x, y) for(int i = x; i <= y; i ++)#define fd(i, x, y) for(int i = x; i >= y; i --)#define max(a, b) ((a) > (b) ? (a) : (b))using namespace std;const int N = 1e6 + 5;int n, s, t, x, y, sum;int final[N], next[N * 2], to[N * 2], tot;int w[N], bz[N], sum_son[N], fa[N];int d[N], bz_d[N];void link(int x, int y) {    next[++ tot] = final[x], to[tot] = y, final[x] = tot;    next[++ tot] = final[y], to[tot] = x, final[y] = tot;}void dg(int x) {    if(x == t) return;    bz[x] = 1;    for(int i = final[x]; i; i = next[i]) {        int y = to[i]; if(bz[y]) continue;        sum_son[x] ++; fa[y] = x; dg(y);    }    bz[x] = 0;}void Build(int x) {    while(x != s) d[++ d[0]] = x, bz_d[x] = 1, x = fa[x]; d[++ d[0]] = x;    fo(i, 2, d[0]) sum += sum_son[d[i]]; sum -= (d[0] - 1);}void dg2(int x) {    if(x == t) return;    bz[x] = 1;    int mx = 0, mx2 = 0;    for(int i = final[x]; i; i = next[i]) {        int y = to[i]; if(bz[y]) continue;        if(!bz_d[y]) w[y] = w[x] + sum_son[y];        dg2(y);        if(w[y] > mx) {            mx2 = mx;            mx = w[y];        } else        if(w[y] > mx2) {            mx2 = w[y];        }    }    w[x] = mx2 + sum_son[x];    bz[x] = 0;}int pd(int m) {    int yige = 0;    fd(i, d[0], 2) {        int dep = d[0] - i + 1;        int ss = 0;        int x = d[i];        for(int j = final[x]; j; j = next[j]) {            int y = to[j]; if(bz_d[y] || fa[y] != x) continue;            if(w[y] + sum > m - yige) ss ++;        }        if(ss > dep - yige) return 0;        yige += ss;        if(m < yige) return 0;        sum -= sum_son[x] - 1;    }    return 1;}int main() {    freopen("compete.in", "r", stdin);    freopen("compete.out", "w", stdout);    scanf("%d %d %d", &n, &t, &s);    fo(i, 1, n - 1) {        scanf("%d %d", &x, &y);        link(x, y);    }    dg(s);    Build(t);    dg2(s);    int ans = 0;    for(int l = 0, r = n; l <= r; ) {        int m = (l + r) / 2;        int sum2 = sum;        if(pd(m)) ans = m, r = m - 1; else l = m + 1;        sum = sum2;    }    printf("%d", ans);}
原创粉丝点击