疫情控制

题面

一个军队越往上走他所管的叶子结点就越多,并且时间越多就越能够满足条件。

于是考虑对于每个军队都先尽量往上跳(先不到根),对于一些有能力到根的把它们到达根之后剩余的时间和现在的位置记录下来(它们可以帮助堵住其他叶子节点),不然的话就让他原地驻扎。

从根的儿子遍历,看这个儿子是否需要驻扎军队,对于需要驻扎的记录下来。

对于一开始记录的军队,如果它们现在的位置需要军队并且它们到达根之后不能回来就原地驻扎就好,不这样的话他就只能去一些到根的距离小于现在位置到根的距离的地方,而这个位置就需要剩余时间比他多的军队来(排了序),而他能干的比他剩余时间多的都能干。

现在再找出可以移动的军队的剩余时间和需要军队的根的儿子到根的距离,对两者排序,一一匹配。

第二个不错

倍增的时候注意先加值,再跳

#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
const int maxn=50005;
int n,m,fa[maxn][25];
ll l,r,ans=-1,sum[maxn][25];
int cnt,head[maxn];
int timer,safe[maxn];
bool need[maxn];
struct edge{
    int x,y,next;
    ll val;
}e[maxn<<1];
struct node{
    ll rest;int id;
    bool operator < (const node a) const {return a.rest>rest;}
};
vector<node> cx;//能到根的军队 
vector<int> a;//军队初始位置 
vector<int> go,want;//军队,根的儿子 

template<class T>inline void read(T &x){
    x=0;int f=0;char ch=getchar();
    while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x= f ? -x : x ;
}

void add(int x,int y,ll val){
    e[++cnt]=(edge){x,y,head[x],val};
    head[x]=cnt;
}

void dfs(int x){
    for(int i=1;i<=20;i++){
        fa[x][i]=fa[fa[x][i-1]][i-1];
        sum[x][i]=sum[x][i-1]+sum[fa[x][i-1]][i-1];
    }
    for(int i=head[x];i;i=e[i].next){
        int y=e[i].y;
        if(y==fa[x][0]) continue;
        fa[y][0]=x;
        sum[y][0]=e[i].val;
        dfs(y);
    }
}

void get(int x,ll rest){
    for(int i=20;~i;i--)
     if(fa[x][i]&&fa[x][i]!=1&&sum[x][i]<=rest){
          rest-=sum[x][i];
          x=fa[x][i];
     }
    if(fa[x][0]==1&&rest>=sum[x][0])
        cx.push_back((node){rest-sum[x][0],x});
    else safe[x]=timer;
}

bool find(int x){
    bool opt=true;//是否是边境。
    if(safe[x]==timer) return false;
    for(int i=head[x];i;i=e[i].next){
        int y=e[i].y;
        if(e[i].y==fa[x][0]) continue;
        opt=false;
        if(find(y)) return true;
    }
    return opt;
}

bool make_plan(){
    sort(want.begin(),want.end());
    unsigned int i=0,j=0;
    while(i<go.size()&&j<want.size()){
        if(go[i]>=want[j]) i++,j++;
        else i++;
    }
    return j==want.size();
}

bool check(ll tot){
    ++timer;
    cx.clear();
    go.clear();
    want.clear();
    for(unsigned int i=0;i<a.size();i++) get(a[i],tot);
    for(int i=head[1];i;i=e[i].next) need[e[i].y]=find(e[i].y);
    sort(cx.begin(),cx.end());
    for(unsigned int i=0;i<cx.size();i++)
     if(need[cx[i].id]&&sum[cx[i].id][0]>cx[i].rest)
          need[cx[i].id]=false;
     else go.push_back(cx[i].rest);
    for(int i=head[1];i;i=e[i].next)
     if(need[e[i].y]) want.push_back(sum[e[i].y][0]);
    return make_plan();
}

int main(){
    read(n);
    for(int i=1;i<n;i++){
        int x,y;ll val;
        read(x);read(y);read(val);
        add(x,y,val);
        add(y,x,val);
        r+=val;
    }
    read(m);
    for(int i=1;i<=m;i++){
        int x;read(x);
        a.push_back(x);
    }
    dfs(1);
    while(l<=r){
        ll mid=(l+r)>>1;
        if(check(mid)) ans=mid,r=mid-1;
        else l=mid+1;
    }
    printf("%lld",ans);
}
/*
10
2 1 3
2 3 4
1 4 7
5 1 9
6 1 2
4 7 9
7 8 8
9 8 8
1 10 2
5
2 8 5 4 2 
*/
疫情控制

 

posted @ 2019-09-24 19:51  _JSQ  阅读(232)  评论(0编辑  收藏  举报