【jzoj3104】【疫情控制】

题目大意

给出一棵带边权树,一些点上有军队,求最少的时间是的叶子结点到根至少经过一个军队。

解题思路

二分答案,能往上跳就尽量往上跳,求出可以跳过根的和需要从根调军队的点,排序后贪心即可。

code

#include<set>
#include
#include
#include
#include
#include
#define LL long long
#define LD double
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a>b)?b:a)
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
int const inf=2147483647;
int const maxn=50000;
int n,m,logn,gra,to[maxn*2+10],p[maxn+10],next[maxn*2+10],begin[maxn+10],
len[maxn*2+10],fa[maxn+10][20],tag[maxn+10];
LL dis[maxn+10],stay[maxn+10];
void insert(int u,int v,int w){
    to[++gra]=v;
    len[gra]=w;
    next[gra]=begin[u];
    begin[u]=gra;
}
void dfs(int now,int pre){
    for(int i=begin[now];i;i=next[i])
        if(to[i]!=pre){
            dis[to[i]]=dis[now]+len[i];
            fa[to[i]][0]=now;
            dfs(to[i],now);
        }
}
bool dfss(int now,int pre){
    if(tag[now])return 1;
    int ok=1;
    for(int i=begin[now];i;i=next[i])
        if(to[i]!=pre){
            ok=0;
            if(!dfss(to[i],now))return 0;
        }
    if(ok)return 0;
    return 1;
}
LL tmp,pp,a[maxn+10],b[maxn+10];
bool check(LL ans){
    fo(i,1,n)tag[i]=stay[i]=0;a[0]=0;
    int cnta=0,cntb=0;
    fo(i,1,m){
        pp=p[i];tmp=ans;
        fd(j,logn,0)
            if((fa[pp][j]>1)&&(dis[pp]-dis[fa[pp][j]]<=tmp)){
                tmp-=dis[pp]-dis[fa[pp][j]];
                pp=fa[pp][j];
            }
        if(dis[pp]-dis[fa[pp][0]]>tmp)tag[pp]=1;
    }
    cntb=0;
    for(int i=begin[1];i;i=next[i])
        if(!dfss(to[i],1))stay[to[i]]=-1;
        else stay[to[i]]=0;
    fo(i,1,m){
        pp=p[i];tmp=ans;
        fd(j,logn,0)
            if((fa[pp][j]>1)&&(dis[pp]-dis[fa[pp][j]]<=tmp)){
                tmp-=dis[pp]-dis[fa[pp][j]];
                pp=fa[pp][j];
            }
        if(dis[pp]-dis[fa[pp][0]]<=tmp){
            if(((stay[pp]!=-1)&&(stay[pp]<=tmp-(dis[pp]-dis[fa[pp][0]])))
                ||(tmp-(dis[pp]-dis[fa[pp][0]])>=dis[pp]))
                a[++cnta]=tmp-(dis[pp]-dis[fa[pp][0]]);
            else if(stay[pp]>tmp-(dis[pp]-dis[fa[pp][0]])){
                a[++cnta]=stay[pp];
                stay[pp]=tmp-(dis[pp]-dis[fa[pp][0]]);
            }else if(stay[pp]==-1){
                stay[pp]=tmp-(dis[pp]-dis[fa[pp][0]]);
                tag[pp]=1;
            }
        }
    }
    cntb=0;
    for(int i=begin[1];i;i=next[i])
        if(!dfss(to[i],1))b[++cntb]=len[i];
    if(cntb>cnta)return 0;
    sort(a+1,a+cnta+1);
    sort(b+1,b+cntb+1);
    int j=1;
    fo(i,1,cntb){
        for(;(j<=cnta)&&(a[j]if(j<=cnta)j++;
        else return 0;
    }
    return 1;
}
int main(){
    freopen("d.in","r",stdin);
    freopen("d.out","w",stdout);
    scanf("%d",&n);
    fo(i,2,n){
        int u,v,w;scanf("%d%d%d",&u,&v,&w);
        insert(u,v,w);insert(v,u,w);
    }
    dfs(1,0);
    logn=log(n)/log(2);
    fo(j,1,logn)
        fo(i,1,n)
            fa[i][j]=fa[fa[i][j-1]][j-1];
    scanf("%d",&m);
    fo(i,1,m)scanf("%d",&p[i]);
    LL l=0,r=5*1e13,mid;
    for(;l!=r;){
        mid=(l+r)/2;
        if(check(mid))r=mid;
        else l=mid+1;
    }
    if(l==5*1e13)printf("-1");
    else printf("%lld",l);
    return 0;
}

你可能感兴趣的:(jzoj,贪心)