ENFP-T型人格患者|

_Youngxy

园龄:3年7个月粉丝:5关注:28

「NOIP2012」疫情控制 题解

传送门

题目描述

H国有 n个城市,这 n 个城市用n−1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点。

H国的首都爆发了一种危害性极高的传染病。当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点。但特别要注意的是,首都是不能建立检查点的。

现在,在 H 国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队。一支军队可以在有道路连接的城市间移动,并在除首都以外的任意一个城市建立检查点,且只能在一个城市建立检查点。一支军队经过一条道路从一个城市移动到另一个城市所需要的时间等于道路的长度(单位:小时)。

请问最少需要多少个小时才能控制疫情。注意:不同的军队可以同时移动。

输入输出格式

输入格式

第一行一个整数n,表示城市个数。

接下来的 n−1行,每行3个整数,u,v,w,每两个整数之间用一个空格隔开,表示从城市 u到城市v 有一条长为 w 的道路。数据保证输入的是一棵树,且根节点编号为 1。

接下来一行一个整数 m,表示军队个数。

接下来一行 m个整数,每两个整数之间用一个空格隔开,分别表示这 m 个军队所驻扎的城市的编号。

输出格式

一个整数,表示控制疫情所需要的最少时间。如果无法控制疫情则输出−1。

输入输出样例

输入样例 #1
4 
1 2 1 
1 3 2 
3 4 3 
2 
2 2
输出样例 #1
3

说明

【输入输出样例说明】

第一支军队在 2号点设立检查点,第二支军队从 2 号点移动到3 号点设立检查点,所需时间为 3 个小时。

【数据范围】

保证军队不会驻扎在首都。

对于 20%的数据,2≤n≤10;

对于 40%的数据,$2≤50,0

对于 60%的数据,$2≤n≤1000,0

对于 80%的数据,2≤n≤10,000;

对于 100%的数据,$2≤m≤n≤50,000,0

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=60002;
int n,m,cnt,na,nb,t;
int hd[N],nxt[N<<1],to[N<<1],f[N][21],army[N];
ll e[N<<1],dis[N][21],mn[N];
int vis[N],xy[N],rb[N];
struct node{
    ll w;
    int id;
}a[N],b[N];

void add(int u, int v, int w){
    nxt[++cnt]=hd[u];
    hd[u]=cnt;
    to[cnt]=v;
    e[cnt]=w;
}
void dfs(int x,int l, ll hg){
    f[x][0]=l,dis[x][0]=hg;
    for(int i=1; i<=t; 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(int i=hd[x]; i!=-1; i=nxt[i]){
        if(to[i]!=l){
            dfs(to[i],x,e[i]);
        }
    }

}

int df(int u,int l){
    int fg=1,flag=0;
    if(vis[u])return 1;
    for(int i=hd[u];i!=-1;i=nxt[i]){
        if(to[i]==l)continue;
        flag=1;
        if(!df(to[i],u)){
            fg=0;
            if(u==1) {
                b[++nb].id=to[i];
                b[nb].w=e[i];
            }
            else return 0;
        }
    }
    if(!flag)return 0;
    return fg;
}
bool cmp(node x,node y){
    return x.w>y.w;
}
int check(ll k){
    int x,now;
    ll s;
    na=nb=0;
    memset(vis,0,sizeof(vis));
    memset(rb,0,sizeof(rb));
    memset(xy,0,sizeof(xy));
    for(int i=1; i<=m; i++){
        x=army[i],s=0;
        for(int j=t; j>=0; j--){
            if(f[x][j]>1 && s+dis[x][j]<=k){
                s+=dis[x][j];
                x=f[x][j];
            }
        } 
        if(f[x][0]==1 && s+dis[x][0]<=k){
            a[++na].w=k-s-dis[x][0];
            a[na].id=i;
            if(!rb[x]||a[na].w<mn[x])
                mn[x]=a[na].w,rb[x]=i;
        }
        else vis[x]=1;
    }
    if(df(1,0))return 1;
    sort(a+1,a+1+na,cmp);
    sort(b+1,b+1+nb,cmp);
    now=1;
    xy[0]=1;
    for(int i=1; i<=nb; i++){
        if(!xy[rb[b[i].id]]){
            xy[rb[b[i].id]]=1;
            continue;
        }
        while(now<=na&&(xy[a[now].id]||a[now].w<b[i].w))++now;
        if(now>na){
            return 0;
        } 
        xy[a[now].id]=1;
    }
    return 1;
}
int main(){
    int x,y,z;
    ll l=0,r=500000,mid,ans=-1;
    scanf("%d",&n);
    t=(int)(log(n)/log(2))+1;
    memset(hd,-1,sizeof(hd));
    for(int i=1; i<n; i++){
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z),add(y,x,z);
    }
    dfs(1,0,0);
    scanf("%d",&m);
    for(int i=1; i<=m; i++){
        scanf("%d",&army[i]);
    }
    while(l<=r){//二分答案
        mid=(l+r)>>1;
        if(check(mid)){
            r=mid-1;
            ans=mid;
        }else {
            l=mid+1;
        }
    }
    printf("%lld",ans);
    return 0;
}

我第一次提交的时候head数组初始化是-1,for循环里面是i

。。。然后卡了一天
啊喂????
那之前没改的时候怎么有90分???

可能是数据太水了

我好不容易相信数据一次,他却让我输的这么彻底

所以提醒各位大大一定不要初始化(自动为0)!!

完结撒花❀
★,°:.☆( ̄▽ ̄)/$:.°★

本文作者:Yvette的博客

本文链接:https://www.cnblogs.com/yvette1217/p/15986951.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   _Youngxy  阅读(69)  评论(0编辑  收藏  举报
评论
收藏
关注
推荐
深色
回顶
收起
点击右上角即可分享
微信分享提示