NOIP2012 Day2 瘟疫传播

题目传送门

【分析】

如果军队数小于首都连接的子节点数,则答案必不满足;
否则二分答案时间,在规定时间中把每支军队尽可能向上提(此处二分),如果无法到达首都(以下统称为根结点)则就地设立检查站。其余军队进入待命,并从到首都后剩余步数从大到小排序。
dfs遍历所有节点,把所有需要设立检查点的子节点加入一个数组,并根据到根结点的距离从大到小排序。
用i和j同时枚举军队和子节点。如果原来子节点有军队驻扎且未被使用,则使用原来的驻扎军队。满足所有子节点则成立,否则不成立。

下面附上代码一份:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=50010;
struct fff
{
    int v,c,nxt;
}edge[maxn<<1];
int head[maxn],tot=0;
int n,m,s,large;
int army[maxn];
int d[maxn],p[maxn][20];
int dist[maxn],st[maxn][20];
int restbj[maxn],restmin[maxn],vis[maxn];

void add_edge(int x,int y,int c)
{
    edge[tot].v=y;
    edge[tot].c=c;
    edge[tot].nxt=head[x];
    head[x]=tot++;
    return ;
}
void dfs(int u,int dep)
{
    d[u]=dep;
    for(int i=head[u];i!=-1;i=edge[i].nxt)
    {
        int v=edge[i].v,c=edge[i].c;
        if(d[v]) continue;
        p[v][0]=u;
        st[v][0]=c;
        dfs(v,dep+1);
    }
    return ;
}
void pre()
{
    s=1;
    dfs(s,1);
    p[s][0]=s;
    st[s][0]=0;
    large=1;
    while(1<<large<=n) large++;
    large--;
    for(int j=1;j<=large;j++)
        for(int i=1;i<=n;i++)
        {
            p[i][j]=p[p[i][j-1]][j-1];
            st[i][j]=st[i][j-1]+st[p[i][j-1]][j-1];
        }
    return ;
}
struct node
{
    int rest,id;
}a[maxn];
struct point
{
    int child,rest;
}b[maxn];
int na,nb;
int used[maxn];

bool cmp1(node x,node y)
{
    return x.rest>y.rest;
}
bool cmp2(point x,point y)
{
    return x.rest>y.rest;
}
bool done_q(int u,int fa)
{
    int ret=1,flag=0;
    if(vis[u]) return 1;
    for(int i=head[u];i!=-1;i=edge[i].nxt)
    {
        int v=edge[i].v;
        if(v==fa) continue;
        flag=1;
        if(!done_q(v,u))
        {
            ret=0;
            if(u==1)
            {
                b[++nb].child=v;
                b[nb].rest=edge[i].c;
            }
            else return 0;
        }
    }
    if(!flag) return 0;
    return ret;
}
bool check(int mid)
{
    na=nb=0;
    memset(vis,0,sizeof(vis));
    memset(restbj,0,sizeof(restbj));
    memset(restmin,0,sizeof(restmin));
    for(int i=1;i<=m;i++)
    {
        int x=army[i],rest=mid;
        for(int j=large;j>=0;j--)
            if(st[x][j]<=rest&&p[x][j]>s)
            {
                rest-=st[x][j];
                x=p[x][j];
            }
        if(p[x][0]==1&&rest>=st[x][0])
        {
            a[++na].rest=rest-st[x][0],a[na].id=i;
            if(!restbj[x]||restmin[x]>a[na].rest)
                restmin[x]=a[na].rest,restbj[x]=i;
        }
        else vis[x]=1;
    }
    if(done_q(s,0)) return 1;
    sort(a+1,a+na+1,cmp1);
    sort(b+1,b+nb+1,cmp2);
    memset(used,0,sizeof(used));
    int j=1;used[0]=1;
    for(int i=1;i<=nb;i++)
    {
        if(!used[restbj[b[i].child]])
        {
            used[restbj[b[i].child]]=1;
            continue;
        }
        while(j<=na&&(used[a[j].id]||a[j].rest<b[i].rest))++j;
        if(j>na)return 0;
        used[a[j].id]=1;
    }
    return 1;
}
int main()
{
    ios::sync_with_stdio(false);
    memset(st,0,sizeof(st));
    memset(army,0,sizeof(army));
    memset(head,-1,sizeof(head));
    cin>>n;
    for(int i=1;i<n;i++)
    {
        int x,y,c;
        cin>>x>>y>>c;
        add_edge(x,y,c);
        add_edge(y,x,c);
    }
    cin>>m;
    for(int i=1;i<=m;i++)
        cin>>army[i];
    pre();
    int l=0,r=1<<28,ans=-1;
    while(l<=r)
    {
        int mid=l+r>>1;
        if(check(mid)) r=mid-1,ans=mid;
        else l=mid+1;
    }
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xyc1719/article/details/80945594