NOIP 2012 疫情控制
题目描述
H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,
也是树中的根节点。
H 国的首都爆发了一种危害性极高的传染病。当局为了控制疫情,不让疫情扩散到边境
城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境
城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点。但特别要注意的是,
首都是不能建立检查点的。
现在,在 H 国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队。一支军队可以在有道路连接的城市间移动,并在除首都以外的任意一个城市建立检查点,且只能在
一个城市建立检查点。一支军队经过一条道路从一个城市移动到另一个城市所需要的时间等
于道路的长度(单位:小时)。
请问最少需要多少个小时才能控制疫情。注意:不同的军队可以同时移动。
输入输出格式
输入格式:第一行一个整数 n,表示城市个数。
接下来的 n-1 行,每行 3 个整数,u、v、w,每两个整数之间用一个空格隔开,表示从
城市 u 到城市 v 有一条长为 w 的道路。数据保证输入的是一棵树,且根节点编号为 1。
接下来一行一个整数 m,表示军队个数。
接下来一行 m 个整数,每两个整数之间用一个空格隔开,分别表示这 m 个军队所驻扎
的城市的编号。
输出格式:共一行,包含一个整数,表示控制疫情所需要的最少时间。如果无法控制疫情则输出-1。
输入输出样例
4 1 2 1 1 3 2 3 4 3 2 2 2
3
说明
【输入输出样例说明】
第一支军队在 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。
NOIP 2012 提高组 第二天 第三题
题解:
贪心,首先一个点要尽可能往上跳,不会往下跳
二分答案t,将每个军队在t时间内尽可能往上跳,用倍增实现
最麻烦的是一个子树内的点要跳到另一个子树
一开始贪心,把能跳到1点的剩余距离存下,再dfs找出需要军队的子树,排序后填入
但这样错了,有70分
因为会有到1还有距离的点x,放下自己的子树去控制别的子树,或者这棵子树必须由x控制
参考了yzh大佬%%%%%orz的博客后知道了
假设军队已经尽可能往上到了x,key[x]表示x能否控制相应子树,如果key[x]&&x!=1 则说明这个点能控制子树,且不参与到军队在不同子树间的转移,到达1点的军队要参与转移,所以不计
mins[x]为经过x子树的剩余距离最小值的军队编号,这个军队守好自己的子树就行了
d[x]表示x子树是否被控制
我们把能到1,且不含于mins的军队按剩余距离排序为q数组
再把未被控制(d[x]==0)的子树按与1的距离排序为c,然后匹配
提供链接orz:https://home.cnblogs.com/u/Yuzao
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 struct Node 7 { 8 int next,to; 9 long long dis; 10 }edge[100001]; 11 struct Que 12 { 13 int id; 14 long long s; 15 }q[100001],c[100001]; 16 int num,head[100001],n,m,fa[100001][21],pos[100001],dep[100001],mins[100001]; 17 long long s[100001][21],ans,bel[100001]; 18 int b[100001],tt,top,du[100001],ddt; 19 bool us[100001],d[100001],key[100001]; 20 void add(int u,int v,long long d) 21 { 22 num++; 23 edge[num].next=head[u]; 24 head[u]=num; 25 edge[num].dis=d; 26 edge[num].to=v; 27 } 28 bool cmp(Que a,Que b) 29 { 30 return a.s>b.s; 31 } 32 bool exam() 33 {int i,j; 34 sort(q+1,q+tt+1,cmp); 35 sort(c+1,c+top+1,cmp); 36 if (tt<top) return 0; 37 for (i=1,j=1;i<=top;i++) 38 { 39 int u=c[i].id; 40 if (mins[u]!=-1&&us[mins[u]]==0) 41 {us[mins[u]]=1;continue;} 42 while (us[q[j].id]&&j<=tt) j++; 43 if (j>tt) return 0; 44 if (q[j].s<c[i].s) return 0; 45 us[q[j].id]=1; 46 } 47 return 1; 48 } 49 bool check(long long w) 50 {int i,j,cnt; 51 top=0;tt=0;cnt=0; 52 memset(mins,-1,sizeof(mins)); 53 memset(d,0,sizeof(d)); 54 memset(us,0,sizeof(us)); 55 for (i=1;i<=m;i++) 56 {int x=pos[i]; 57 long long sum=w; 58 for (j=20;j>=0;j--) 59 { 60 if (fa[x][j]!=0&&s[x][j]<=sum) 61 { 62 sum-=s[x][j]; 63 x=fa[x][j]; 64 } 65 } 66 if (du[x]==1) cnt++; 67 if (x==1) 68 { 69 tt++; 70 q[tt].id=tt;q[tt].s=sum; 71 if (mins[bel[pos[i]]]==-1) mins[bel[pos[i]]]=tt; 72 if (sum<q[mins[bel[pos[i]]]].s) mins[bel[pos[i]]]=tt; 73 } 74 else if (key[x]) d[bel[x]]=1; 75 } 76 if (cnt==ddt) return 1; 77 for (i=head[1];i;i=edge[i].next) 78 { 79 int v=edge[i].to; 80 if (d[v]==0) 81 { 82 top++; 83 c[top].id=edge[i].to; 84 c[top].s=edge[i].dis; 85 } 86 } 87 if (!top) return 1; 88 return exam(); 89 } 90 void prework(int x,int last) 91 {int i; 92 if (key[last]) key[x]=1; 93 else key[x]=0; 94 if (du[last]>2&&last!=1) key[x]=0; 95 for (i=head[x];i;i=edge[i].next) 96 { 97 int v=edge[i].to; 98 if (v!=last) 99 { 100 prework(v,x); 101 } 102 } 103 } 104 void belon(int x,int pa,int be) 105 {int i; 106 bel[x]=be; 107 for (i=head[x];i;i=edge[i].next) 108 { 109 int v=edge[i].to; 110 if (v!=pa) 111 { 112 belon(v,x,be); 113 } 114 } 115 } 116 void dfs(int x,int pa) 117 {int i; 118 dep[x]=dep[pa]+1; 119 for (i=1;i<=20;i++) 120 { 121 fa[x][i]=fa[fa[x][i-1]][i-1]; 122 s[x][i]=s[x][i-1]+s[fa[x][i-1]][i-1]; 123 } 124 for (i=head[x];i;i=edge[i].next) 125 { 126 int v=edge[i].to; 127 if (v!=pa) 128 { 129 fa[v][0]=x; 130 s[v][0]=edge[i].dis; 131 dfs(v,x); 132 } 133 } 134 } 135 int main() 136 {int i,u,v; 137 long long w,sum=0,l,r; 138 cin>>n; 139 for (i=1;i<=n-1;i++) 140 { 141 scanf("%d%d%lld",&u,&v,&w); 142 add(u,v,w); 143 add(v,u,w); 144 du[u]++;du[v]++; 145 sum+=w; 146 } 147 for (i=1;i<=n;i++) 148 if (du[i]==1) ddt++; 149 cin>>m; 150 for (i=1;i<=m;i++) 151 scanf("%d",&pos[i]); 152 dfs(1,0); 153 for (i=head[1];i;i=edge[i].next) 154 belon(edge[i].to,1,edge[i].to); 155 key[0]=1; 156 prework(1,0); 157 l=0;r=sum; 158 while (l<=r) 159 { 160 long long mid=(l+r)/2; 161 //cout<<mid<<endl; 162 if (check(mid)) ans=mid,r=mid-1; 163 else l=mid+1; 164 } 165 if (ans) 166 cout<<ans; 167 else cout<<-1; 168 }