疫情控制

来源:互联网 发布:软件著作权申请要求 编辑:程序博客网 时间:2024/05/02 00:57

传送门
思路:贪心+二分。
首先我们的军队肯定是越往上越好。
那么我们二分一个时间,让军队在这个时间内尽可能的向上走。然后跑DFS去看看是否封锁了所有的边境城镇。
如果一个子树上根本没有军队怎么办。那么只能从其他子树调过来了。
将可以到根节点并且时间有富裕的军队所剩余的时间排序。
然后把没有军队的子树的时间也排序,找一个时间最相近的去到那颗子树上是最优的。
预处理倍增距离和祖节点

#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#define ll long longusing namespace std;const ll maxm=50105; ll head[maxm],net[2*maxm],to[2*maxm],cost[2*maxm];ll cnt,jd[maxm],f[maxm][19];ll dis[maxm][19],mindis[maxm];//dis表示i向上2^j层的时间,f表示i向上2^j层的地方 bool vis[maxm],use[maxm];ll have[maxm],tot1,tot2;ll n;struct node{    ll id;    ll rest;};node a[maxm],b[maxm];bool comp(node x,node y){    return x.rest>y.rest;}void add(ll x,ll y,ll c){    cnt++;    to[cnt]=y;    cost[cnt]=c;    net[cnt]=head[x];    head[x]=cnt;}void dfs(ll x,ll fat,ll Dis){    dis[x][0]=Dis,f[x][0]=fat;    for(ll i=1;i<=17;i++)    {        f[x][i]=f[f[x][i-1]][i-1];        dis[x][i]=dis[x][i-1]+dis[f[x][i-1]][i-1];    }    for(ll i=head[x];i;i=net[i])     if(to[i]!=fat)      dfs(to[i],x,cost[i]);}bool ok(ll x,ll fat){    bool f1=1,f2=0;    if(vis[x]) return 1;    for(ll i=head[x];i;i=net[i])    if(to[i]!=fat)    {        f2=1;        if(ok(to[i],x)==0)        {            f1=0;            if(x==1) b[++tot2].rest=cost[i],b[tot2].id=to[i];            else return 0;        }    }    if(!f2) return 0;    return f1;}bool check(ll mid,ll q){    //return 0;    //printf("%d\n",q);     memset(a,0,sizeof(a));    memset(b,0,sizeof(b));    memset(vis,0,sizeof(a));    memset(use,0,sizeof(use));    memset(have,0,sizeof(have));    tot1=0,tot2=0;    for(ll i=1;i<=q;i++)    {        ll x=jd[i],sum=0;        //printf("hhhhh\n");        for(ll j=17;j>=0;j--)         if(f[x][j]>1&&sum+dis[x][j]<=mid)          sum+=dis[x][j],x=f[x][j];        if(f[x][0]==1&&dis[x][0]+sum<=mid)        {         a[++tot1].rest=mid-dis[x][0]-sum,a[tot1].id=i;         if(!have[x]||a[tot1].rest<mindis[x])          mindis[x]=a[tot1].rest,have[x]=i;        }        else         vis[x]=1;    }    if(ok(1,0)) return 1;    sort(a+1,a+tot1+1,comp);    sort(b+1,b+tot2+1,comp);    ll now=1;    use[0]=1;    for(ll i=1;i<=tot2;i++)    {        //return 0;        if(use[have[b[i].id]]==0)        {            use[have[b[i].id]]=1;            continue;        }        while(now<=tot1&&(use[a[now].id]||a[now].rest<b[i].rest))++now;        if(now>tot1) return 0;        use[a[now].id]=1;        //printf("%lld %lld %lld\n",mid,b[i].id,b[i].rest);    }    //puts("2333");    return 1;}int main(){    ll q;    scanf("%lld",&n);    for(ll i=1,x,y,c;i<n;i++)     scanf("%lld%lld%lld",&x,&y,&c),add(x,y,c),add(y,x,c);    scanf("%lld",&q);     //printf("%d\n",q);    for(ll i=1;i<=q;i++)     scanf("%lld",&jd[i]);     dfs(1,0,0);    //printf("%lld %lld\n",dis[2][0],dis[4][1]);    ll l=0,r=1e9+100;    while(l<=r)    {        ll mid=(l+r)/2;        if(check(mid,q)) r=mid-1;        else l=mid+1;    }    if(r==1e9+100) l=-1;    printf("%lld",l);}