疫情控制

传送门

解法:

这道题虽然思路不会太难

但是代码较难实现 可能是我太菜了

思路就是二分答案

在答案范围内将军队尽量向上提(注意不能提到跟节点)

然后考虑子树见转移

对于根节点的子节点进行转移

要是爬上来消耗掉的时间还足以转移改军队

则将其加到根节点上准备转移

对于要救助的子节点进行转移即可

请参考代码(调了我一天) 要是你能看懂

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#define inf 2000000000
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dwn(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
typedef long long ll;
int n,m,root=1,cnt=0,dep[50010],f[50010][18],lg2[50010],pnt[50010];
vector<ll> pos[50010];vector<int> rec;
bool v[50010];
ll d[50010],ans=-1,up=0;
queue<int> que;
int head[50010],tot=1;
struct EDGE
{
    int to,nxt,d;
}edge[100010];
void add(int u,int v,int d)
{
    edge[++tot].nxt=head[u];
    edge[tot].to=v;
    edge[tot].d=d;
    head[u]=tot;
}
void bfs()
{
    d[root]=0,dep[root]=1;
    que.push(root);
    while(!que.empty())
    {
        int x=que.front();que.pop();
        for(int i=head[x];i;i=edge[i].nxt)
        {
            int y=edge[i].to;
            if(dep[y]) continue;
            d[y]=d[x]+edge[i].d;
            up=max(up,d[y]);
            dep[y]=dep[x]+1;
            f[y][0]=x;
            rep(i,1,lg2[dep[y]]) f[y][i]=f[f[y][i-1]][i-1];
            que.push(y);
        }
    }
}
bool sortcmp(ll a,ll b)
{
    return a>b;
}
bool recsort(int a,int b)
{
	return a>b;
}
void dfs(int x)
{
    if(v[x]) return;
    for(int i=head[x];i;i=edge[i].nxt)
    {
        int y=edge[i].to;
        if(dep[x]>dep[y]) continue;
        dfs(y);
        v[x]=v[y];
        if(!v[x]) return;
    }
}
bool check(ll k)
{
    memset(v,0,sizeof(v));
    rep(i,1,n)pos[i].clear();
	rec.clear();
    rep(i,1,m)
    {
        int y=pnt[i];ll dis=k;
        dwn(i,lg2[dep[y]-2],0)
            if(d[y]-d[f[y][i]]<=dis&&dep[f[y][i]]>=2)
                dis=dis-d[y]+d[f[y][i]],y=f[y][i];
        if(dep[y]==2){pos[y].push_back(dis);}
        v[y]=1;
    }
    for(int i=head[root];i;i=edge[i].nxt)
    {
        int x=edge[i].to;
        v[x]=0;
        dfs(x);
        if(pos[x].empty()&&!v[x]){rec.push_back(edge[i].d);continue;}
        sort(pos[x].begin(),pos[x].end(),sortcmp);
        for(int j=0;j<int(pos[x].size())-(v[x]?0:1);++j)
        {
            ll dis=pos[x][j];
            if(dis>=edge[i].d) pos[root].push_back(dis-edge[i].d);
        }
        if(!v[x]&&pos[x][pos[x].size()-1]>=2*edge[i].d)
			pos[root].push_back(pos[x][pos[x].size()-1]-edge[i].d),rec.push_back(edge[i].d);
    }
    if(rec.empty()) return 1;
    if(pos[root].size()<rec.size()) return 0;
    sort(rec.begin(),rec.end(),recsort);
    sort(pos[root].begin(),pos[root].end(),sortcmp);
    for(int i=0;i<rec.size();++i)
    {
        if(pos[root][i]<rec[i]) return 0;
    }
    return 1;
}
int main()
{
    scanf("%d",&n);
    rep(i,2,50000) lg2[i]=lg2[i>>1]+1;
    rep(i,1,n-1)
    {
        int u,v,d;
        scanf("%d%d%d",&u,&v,&d);
        if(u==1||v==1) cnt++;
        add(u,v,d),add(v,u,d);
    }
    bfs();
    scanf("%d",&m);
    if(cnt>m) {printf("-1\n");return 0;}
    rep(i,1,m)
    {
        scanf("%d",&pnt[i]);
    }
    ll l=0,r=2*up;
    while(l<=r)
    {
        ll mid=(l+r)>>1;
        if(check(mid)) ans=mid,r=mid-1;
        else l=mid+1;
    }
    printf("%lld\n",ans);
    return 0;
}

posted @ 2019-07-07 19:16  zmy蒟蒻  阅读(191)  评论(0编辑  收藏  举报