疫情控制

1.预处理倍增
所有的军队都要尽可能地往根节点走。
那么我们可以dfs一遍,将倍增要用的一些值都处理好
2.二分答案
所以就是二分啦,二分一个答案。
3.上提军队
使用倍增的方法将军队在二分出的答案限制内尽力往上,不过不可以到根节点。
4.处理剩余路程
记录还可以走多少
5.dfs找能走的子树
找需要走的子树
6.走子树,走到第一个叉
将我们已经记录好了的可以到根节点的军队按照剩余路程从大到小排序。
然后贪心,用最长的更新走最长的
这样我们就可以判断当前二分出的答案是否可行了。

#include
#include 
#include
#include
#define ll long long
using namespace std;
const int M=51000;
struct st{
    ll rest,id;
}; 
st a[M],b[M];
ll vis[M],used[M],dep[M][34],flag[M],f[M][34],jd[M],na,nb,restbj[M],restmin[M];
ll n,m;
ll tot,head[M],nex[M*4],cos[M*2],to[M*2];
void add(ll x,ll y,ll z){
    nex[++tot]=head[x];
    to[tot]=y;
    cos[tot]=z;
    head[x]=tot;
}
ll cmp(const st&a,const st&b){
    return a.rest>b.rest;
}
void dfs(ll x,ll las,ll h){
    f[x][0]=las,dep[x][0]=h;
    for(int i=1;i<=18;++i){
        f[x][i]=f[f[x][i-1]][i-1];
        dep[x][i]=dep[x][i-1]+dep[f[x][i-1]][i-1];
    }
    for(int i=head[x];i;i=nex[i])
        if(to[i]!=las)dfs(to[i],x,cos[i]);
}
void dfs2(ll o,ll s){
    ll x=jd[o],num=0;
    for(ll i=18;i>=0;i--){

        if(f[x][i]>1&&num+dep[x][i]<=s) num+=dep[x][i],x=f[x][i];

    }
    //printf("mm%dmm",s);
        if(num+dep[x][0]<=s&&f[x][0]==1){
            a[++na].rest=s-num-dep[x][0];a[na].id=o;
            if(!restbj[x]||restmin[x]>(s-num-dep[x][0]))

                restmin[x]=s-num-dep[x][0],restbj[x]=o;

        }
        else vis[x]=1;
}
ll dfs3(ll x,ll fat){

    ll bj=1,i,bbj=0;
    if(vis[x])return 1;
    for(ll i=head[x];i;i=nex[i]){
        ll tmp=to[i];

        if(tmp==fat)continue;
        bbj=1;
        if(!dfs3(tmp,x)){
            bj=0;
            if(x==1) b[++nb].id=to[i],b[nb].rest=cos[i];
            else return 0;
        }
    }

    if(!bbj)return 0;
    return bj;
}
ll check(ll x){
    na=0,nb=0;
    memset(vis,0,sizeof vis);
    memset(used,0,sizeof used);
    memset(restbj,0,sizeof restbj);
//  memset(restmin,127,sizeof restmin);
    for(ll i=1;i<=m;i++)
    dfs2(i,x);


    if(dfs3(1,0)) return 1;
     sort(a+1,a+1+na,cmp),sort(b+1,b+1+nb,cmp);
     //for(ll i=1;i<=na;i++) printf("-%d ",a[i].id);
     //printf("\n");
     ll now=1;used[0]=1;
    for(ll i=1;i<=nb;i++){
        if(!used[restbj[b[i].id]]){
        used[restbj[b[i].id]]=1;continue;}
        while(now<=na&&(used[a[now].id]||a[now].restif(now>na)return 0;
        used[a[now].id]=1;
    }
    return 1;
}
int main(){
    scanf("%lld",&n);
    for(ll i=1;iscanf("%lld%lld%lld",&x,&y,&z);
        add(x,y,z);
        add(y,x,z);

    }


    dfs(1,0,0);



    //for(ll j=1;j<=n;j++)
        //printf("--%d ",dep[j]);

    scanf("%lld",&m);
    for(ll i=1;i<=m;i++) {
        scanf("%lld",&jd[i]);

    }
        //printf("1");
    ll l=1,r=1000000009;
    while(l<=r){
        ll mid=(l+r)>>1;
        ll w=check(mid);
        if(w) r=mid-1;
        else l=mid+1;
    }
    printf("%lld",l);

} 

你可能感兴趣的:(2016~2017,二分查找,倍增)