P1084 [NOIP 2012] epidemic control

\(Description\)

Questions face
to give you a \ (n \) nodes weighted tree, you have to tell \ (m \) th node army and stationed their troops elapsed time of one side is the weight of this edge, requires mobile army (military all move simultaneously, can overlap), such that each one has its troops from the root to the leaf nodes, the root node can not be stationed in military, leaf nodes may military presence. The minimum time required to complete the deployment is.

\(Solution\)

Since all troops can be moved at the same time, so the completion of the deployment time is the slowest time of arrival specify the location of the military spending, which is the maximum amount of time to make the shortest, so this question is summarized apparently dichotomous answer.
So how \ (check \) it, taking into account the military at one point, all of the paths of his sub-trees have been legitimate, so let him try to move up, must make more legitimate path number, so in the second separation in time, so that each army go up as much as possible, and recorded his final position.
If an army can reach the root node, then he can go to the other sub-tree root node. So he came to us with the following structure record, then \ (DFS \) the whole tree, if the root of a subtree is not completely covered, then we record what number Fengyun tree, but they need other troops from after another sub-tree root to come and help, according to the greedy, it is clear these troops come from just root root shortest distance covered by this sub-tree and all points within the sub-tree (that is, through the sub-tree - the root of this side).

In summary, open two structures, a root node can go to support the number of troops and the time he can go to reach the record, a record not covered by the sub-tree root node, and the distance to the root of his, the two descending structural body, a long time remaining to cover a longer distance subtree ( if the answer is so greedy solvability must be right, will be able to find solutions to a combination method ), if the cover is not no solution. But note that there may be a sub-tree has its own army can be covered, but he went to the root node, in \ (DFS \) during Fengyun sub-tree will be considered as not covering this situation from all of us out from the sub-tree to elect army shortest remaining time used to cover, this is also a right greedy, long time remaining to cover other sub-tree. So we recorded all the sub-tree root node to go out of the army minimum remaining time and number, when the match can not be overwritten look at their own army, then mark used, if not to find the maximum to cover.

In addition to go up process can be optimized using the multiplier, as well as attention to open \ (Long \ Long \) .

For more details, see the code

\(Code\)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define re register
#define maxn 50010
#define ll long long
using namespace std;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct Edge{
    int v,w,nxt;
}e[maxn<<2];
bool flag,flag2,okk[maxn];
ll tmp1;
ll rest[maxn],dis[maxn][23];
int used[maxn];
int x,y,z,head[maxn],cnt,n,m,loc[maxn];
int restmin[maxn],restid[maxn],vis[maxn];
int cnt2,na,nb,f[maxn][23];
struct node{
    int id;
    ll res;
}a[maxn],b[maxn];
inline void add(int u,int v,int w)
{
    e[++cnt].v=v;
    e[cnt].w=w;
    e[cnt].nxt=head[u];
    head[u]=cnt;
}
void dfs1(int now,int fa,ll w)//预处理 
{
    //fat[now]=fa;
    f[now][0]=fa;
    dis[now][0]=w;
    for(re int i=1;i<=18;++i)
    {
        f[now][i]=f[f[now][i-1]][i-1];//f[i][j]表示从i往上跳2^j步到达的点 
        dis[now][i]=dis[now][i-1]+dis[f[now][i-1]][i-1];//dis[i][j]表示从i节点向上跳2^j步所经过的路程 
    }
    for(int i=head[now];i;i=e[i].nxt)
    {
        int ev=e[i].v;
        if(ev==fa) continue;
         dfs1(ev,now,e[i].w);
    }
}
bool cmp(node A,node B)
{
    return A.res>B.res;//按 剩余时间/需要的时间 从大到小排序 
}
void dfs2(int now,int fa)
{
   bool h=false;
   if(vis[now])  return ;//访问过就回溯 
   for(int i=head[now];i;i=e[i].nxt)
   {
     int ev=e[i].v;
     
     if(ev==fa) continue;
     h=true;//h记录有没有儿子,叶子节点没有儿子 
     dfs2(ev,now);
   }
   if(!h)  flag=false;//如果是叶子节点还没有回溯就代表这条路径没被占领 
}
bool check(ll co)
{
    int x;
    ll num=0;//开long long 
    na=nb=0;//表示结构体大小,注意清零 
    memset(vis,0,sizeof(vis));   //标记最终军队在哪些点 
    memset(restid,0,sizeof(restid));//restid[i]表示从i这颗子树中出去的军队中,剩余时间最短的编号 
    memset(used,0,sizeof(used));
    for(int i=1;i<=m;++i)
    {
        x=loc[i],num=0;//num表示条的距离 
        for(int j=17;j>=0;--j)
         if(f[x][j]>1&&num+dis[x][j]<=co)//倍增,注意先不要条到根节点 
          num+=dis[x][j],x=f[x][j];
        if(f[x][0]==1&&num+dis[x][0]<=co)//假如可以跳到根节点 
        {
            a[++na].res=co-num-dis[x][0],a[na].id=i;//a数组记录军队编号和剩余时间 
            if(!restid[x]||a[na].res<restmin[x])//restmin记录最短剩余时间,不清空的话要加前面!restid[x]判断 
             restmin[x]=a[na].res,restid[x]=i;
        }
        else vis[x]=1;  //到不了根节点再标记位置 
    }
    for(re int i=head[1];i;i=e[i].nxt)
    {
        int ev=e[i].v;
        flag=true;
        dfs2(ev,1);//每颗根节点的子树dfs,没被覆盖则记录 
        if(!flag) b[++nb].id=ev,b[nb].res=e[i].w;
    }
    sort(a+1,a+na+1,cmp);
    sort(b+1,b+nb+1,cmp);//从大到小排序 
    x=1,used[0]=1;//x在军队数组中扫描 
    for(re int i=1;i<=nb;++i)
    {
        if(!used[restid[b[i].id]]){used[restid[b[i].id]]=1;continue;}//如果从这颗子树中出去的剩余时间最短的 
        //补充:假如用过为啥不去找次小值,因为已经用过说明这个军队去别的地方了,比他大的都用过了 
        while(x<=na&&(used[a[x].id]||a[x].res<b[i].res)) ++x;//往后找,用过的别用 
        if(x>na) return false;
        used[a[x].id]=1;//这里也别忘标记 
    }
    return true;
    
}
ll erfen()
{
    ll l=0,r=tmp1;
    while(l<=r)
    {
        ll mid=(l+r)>>1;
        if(check(mid)) r=mid-1;
        else l=mid+1;
    }
    return l;
}
int main()
{
    n=read();
    for(re int i=1;i<n;++i)
    {
        x=read(),y=read(),z=read();
        add(x,y,z);
        add(y,x,z);
        tmp1+=z;//二分边界 
    }
    m=read();
    for(re int i=1;i<=m;++i) loc[i]=read();
    dfs1(1,0,0);
    printf("%lld\n",erfen());//输出用long long 
    return 0;
}

Guess you like

Origin www.cnblogs.com/Liuz8848/p/11708806.html