问题标题: 酷町堂:2901 疾病检查

0
0
已解决
王子桐
王子桐
高级光能
高级光能

膜拜做出来的大佬!!!

王子桐在2021-03-07 20:35:03追加了内容

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

输入描述 Input Description

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

输出描述 Output Description

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

样例输入 Sample Input

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

样例输出 Sample Output

3

数据范围及提示 Data Size & Hint

【输入输出样例说明】
第一支军队在 2 号点设立检查点,第二支军队从 2 号点移动到 3 号点设立检查点,所需时间为 3 个小时。
【数据范围】
保证军队不会驻扎在首都。
对于 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。

NOIP2012提高组D2第3题

我哭了!


0
已采纳
陈正朔
陈正朔
初级光能
初级光能

这题要用树,队列,二分,广度优先搜索,很难

0
叶珍含
叶珍含
新手守护
新手守护
#include <bits/stdc++.h>
using namespace std;
const int Max=50005;
int n,m,size,l,r,mid,tot1,tot2;
int first[Max],num[Max],f[Max][18],d[Max][18],p[Max],vis[Max];
struct bian{int to,next,len;};
bian edge[Max<<1];
struct shu{int id,len;};
shu a[Max],b[Max];
 
inline int get_int()
{
	int x=0,f=1;
	char c;
	for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
	if(c=='-') f=-1,c=getchar();
	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
	return x*f;
}
 
inline void build(int x,int y,int z)
{
	edge[++size].next=first[x];
	first[x]=size;
	edge[size].to=y,edge[size].len=z;
}
 
inline void dfs(int point,int fa)
{
	for(int u=first[point];u;u=edge[u].next)
	{
	  int to=edge[u].to;
	  if(to==fa) continue;
	  f[to][0]=point,d[to][0]=edge[u].len;
	  dfs(to,point);
	}
}
 
inline void pre()
{
	for(int j=1;j<=16;j++)
	   for(int i=1;i<=n;i++)
	     if(f[i][j-1]) f[i][j]=f[f[i][j-1]][j-1],d[i][j]=d[i][j-1]+d[f[i][j-1]][j-1];
}
 
inline void search(int point,int fa)
{
	if(vis[point]) return;
	vis[point]=1;int tag=0;
	for(int u=first[point];u;u=edge[u].next)
	{
	  int to=edge[u].to;
	  if(to==fa) continue;
	  tag=1;
	  search(to,point);
	  vis[point]&=vis[to];
	}
	if(!tag) vis[point]=0; 
}
 
inline bool comp(const shu &a,const shu &b){return a.len<b.len;}
inline bool check(int mid)
{
	tot1=tot2=0;
	for(int i=1;i<=n;i++) vis[i]=0;
	for(int i=1;i<=m;i++)
	{
	  int sum=0,x=p[i];
	  for(int k=16;k>=0;k--)
	  	if(f[x][k]>1&&sum+d[x][k]<=mid) sum+=d[x][k],x=f[x][k];
	  if(f[x][0]==1&&sum+d[x][0]<=mid) a[++tot1].len=mid-sum-d[x][0],a[tot1].id=x;
	  else vis[x]=1;
	}
	search(1,0);
	if(vis[1]) return 1;
	for(int u=first[1];u;u=edge[u].next)
	  if(!vis[edge[u].to]) b[++tot2].len=edge[u].len,b[tot2].id=edge[u].to;
	sort(a+1,a+tot1+1,comp),sort(b+1,b+tot2+1,comp);
	if(tot1<tot2) return 0;
    int tag=1;
    for(int i=1;i<=tot1;i++)
    {
      if(!vis[a[i].id]) vis[a[i].id]=1; 
      else if(a[i].len>=b[tag].len) vis[b[tag].id]=1;
      while(tag<=tot2&&vis[b[tag].id]) tag++;
      if(tag>tot2) return 1;
    }
    return tag>tot2;
}
 
int main()
{
	n=get_int();
	for(int i=1;i<n;i++)
	{
	  int x=get_int(),y=get_int(),z=get_int();
	  build(x,y,z),build(y,x,z);
	}
	m=get_int();
	for(int i=1;i<=m;i++) p[i]=get_int();
	dfs(1,0);
	pre();
	l=0,r=1e9;int tag=0;
	while(l<r)
	{
	  mid=(l+r)>>1;
	  if(check(mid)) tag=1,r=mid;
	  else l=mid+1;
	}
	if(tag) cout<<r<<"\n";
	else cout<<"-1\n";
	return 0; 
}

不用谢我,我也是网上抄的,记得自首!!!

叶珍含在2021-03-10 18:49:50追加了内容

100多行,你要是不嫌累,你就开始打代码吧!!!

叶珍含在2021-03-10 18:49:58追加了内容

100多行,你要是不嫌累,你就开始打代码吧!!!

0
我要回答