NOIP2012DAY2T3【疫情控制】

来源:互联网 发布:软件著作权的好处 编辑:程序博客网 时间:2024/05/02 04:35
 

Description

H国有n个城市,这n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点。 H国的首都爆发了一种危害性极高的传染病。当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点。但特别要注意的是,首都是不能建立检查点的。 现在,在H国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队。一支军队可以在有道路连接的城市间移动,并在除首都以外的任意一个城市建立检查点,且只能在一个城市建立检查点。一支军队经过一条道路从一个城市移动到另一个城市所需要的时间等于道路的长度(单位:小时)。 请问最少需要多少个小时才能控制疫情。注意:不同的军队可以同时移动。

Input Format

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

Output Format

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

Sample Input

4 1 2 1 1 3 2 3 4 3 2 2 2 

Sample Output

3

Hint

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

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

对于40%的数据,2 ≤n≤50, 0< w< 10^5;

对于60%的数据,2 ≤ n≤1000, 0< w <10^6;

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

对于100%的数据,2≤m≤n≤50,000,0 < w <10^9。

【题解】

      先申明 个人觉得这题特别恶心,我大概是花一午想这道题,一小时多写完,调了40分钟,很多小处理都很关键但由于处理特别多,本文只讲本题的大致思路 有许多处理读者请结合代码自行yy
      下面进入题解部分
       二分答案 树上倍增
       由于难以直接求答案 所以采用二分答案的做法 对于二分出来的mid验证它的可行性
       起先是一个简单的贪心想法:对于同样的时间 军队肯定是越靠近根节点越优 所以可以用树上倍增的做法记录下每个军队在mid的时间内最往上能到达的节点
       对于能走到的根节点的军队记录下它到根节点之后剩余时间lasti,以及它是从根节点的哪个子节点ai所在的子树过来的(备用)
       还要用简单的树形动归求一下根节点的哪几棵子树没被完全覆盖(结合代码中过程find以及bo数组处理理解)
       接下来是一个比较难想到的贪心,对于每个到根节点的节点,若它的lasti以及不足以让它回到ai(见上)且ai所在的子树并没有被完全覆盖则让它退回到ai(若它已经不够回去的话 如果你不让它退回去 则你还需要找一个last大于它的节点来覆盖这棵子树 那么就浪费了一个last大的节点 不够优)(结合代码对arm数组的修改操作理解)
       然后就是用剩下的部队覆盖还没完全被覆盖的子树了
       先把子树按照子树根节点到根节点的距离排序(说得有点玄学 结合代码ci数组理解)以及军队按照last排序
      用i,j分别记录当前ci 和arm处理到的位置扫一遍过去就行(比较简单 不做解释 结合代码理解)
      详见代码
      
#include <algorithm>#include <iostream>#include <cstdlib>#include <cstring>#include <string>#include <cstdio>#include <queue>#include <ctime>#include <vector>using namespace std;int num,i,j,k,m,n,x,y,z,first[50005],up[50005][20],tot,fa[50005],bo[50005],a[50005],line[50005];long long g[50005][20],l,r,mid,ans;struct info  {  int ar,next,l;  }tree[100005];struct army  {  long long come,last;  }arm[50005];struct city  {  int no,l;  }ci[50005];bool cmp1(army x,army y){return x.come<y.come;}bool cmp2(army x,army y){return x.last<y.last;}bool cmp3(city x,city y){return x.no<y.no;}bool cmp4(city x,city y){return x.l<y.l;}void add(int x,int y,int z)  {  num++;tree[num]=(info){y,first[x],z};first[x]=num;  }int getfa(int x)  {  if (fa[x]==x) return x;else return fa[x]=getfa(fa[x]);  }void dfs(int u,int fat)  {  int i,v,pd=0;fa[u]=u;  for (i=first[u];i;i=tree[i].next)    {    v=tree[i].ar;    if (v==fat) continue;    dfs(v,u);up[v][0]=u;g[v][0]=tree[i].l;//pd=1;    //child[u]+=child[v];    if (u!=1) fa[v]=u;  }//if (pd==0) child[v]=1,tot++;  }void find(int u,int fat)  {  int i,v,pd=0;  for (i=first[u];i;i=tree[i].next)    {    v=tree[i].ar;    if (v==fat) continue;    find(v,u);pd=1;      if (bo[v]!=-1&&bo[u]!=-1) bo[u]+=bo[v];  }if (pd==0&&bo[u]!=-1) bo[u]=1;  }bool pd(long long mid)  {  int i,j,l=0,x,sum;long long k;memset(bo,0,sizeof(bo));     for (i=1;i<=m;i++)   {    k=mid;x=a[i]; for (;g[x][0]<=k;)   {    for (j=0;g[x][j]<=k;j++);j--;    k-=g[x][j];x=up[x][j];   }  bo[x]=-1; if (x==1) arm[++l]=(army){getfa(a[i]),k};   }find(1,-1);k=0;for (i=1;i<=l;i++)  {    if (line[arm[i].come]>arm[i].last&&bo[arm[i].come]>0)   bo[arm[i].come]=-1,swap(arm[i],arm[l]),l--,i--;      }for (i=first[1];i;i=tree[i].next)  if (bo[tree[i].ar]>0) ci[++k]=(city){tree[i].ar,tree[i].l};sort(arm+1,arm+l+1,cmp2);sort(ci+1,ci+k+1,cmp4);for (j=i=1,sum=0;j<=k;j++)  for (;i<=l;i++)    if (arm[i].last>=ci[j].l)   {  i++;sum++;break;  }     if (sum==k) return 1;else return 0;  }int main()   {  scanf("%d",&n);  for (i=1;i<n;i++)    scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z);  up[1][0]=1;g[1][0]=1e15;dfs(1,-1);    for (i=1;i<19;i++)      for (j=1;j<=n;j++)        {        up[j][i]=up[up[j][i-1]][i-1];        g[j][i]=g[j][i-1]+g[up[j][i-1]][i-1];}l=0;r=1e15;for (i=first[1];i;i=tree[i].next) line[tree[i].ar]=tree[i].l;scanf("%d",&m);for (i=1;i<=m;i++) scanf("%d",&a[i]);ans=-1;for (;l<=r;)  {  mid=(l+r)/2;  if (pd(mid)) ans=mid,r=mid-1;else l=mid+1;  }printf("%lld",ans);  }

      
0 0
原创粉丝点击