noip2012 疫情控制
题目描述
H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点。
H 国的首都爆发了一种危害性极高的传染病。当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点。但特别要注意的是,首都是不能建立检查点的。
现在,在 H 国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队。一支军队可以在有道路连接的城市间移动,并在除首都以外的任意一个城市建立检查点,且只能在一个城市建立检查点。一支军队经过一条道路从一个城市移动到另一个城市所需要的时间等于道路的长度(单位:小时)。
请问最少需要多少个小时才能控制疫情。注意:不同的军队可以同时移动。
输入输出格式
输入格式:
第一行一个整数 n,表示城市个数。
接下来的 n-1 行,每行 3 个整数,u、v、w,每两个整数之间用一个空格隔开,表示从城市 u 到城市 v 有一条长为 w 的道路。数据保证输入的是一棵树,且根节点编号为 1。
接下来一行一个整数 m,表示军队个数。
接下来一行 m 个整数,每两个整数之间用一个空格隔开,分别表示这 m 个军队所驻扎的城市的编号。
输出格式:
共一行,包含一个整数,表示控制疫情所需要的最少时间。如果无法控制疫情则输出-1。
输入输出样例
说明
【输入输出样例说明】
第一支军队在 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 提高组 第二天 第三题
———————————————————————————————————————
这道题首先二分其实挺明显的 数据范围和最大最小 最小最大这种都是很明显的二分
考虑二分答案 那么我们发现如果一只军队不能到达首都 那么我们肯定暴力把他提到最高的位置
这样肯定是最优的 然后我们再考虑那些可以到首都然后进入首都的某个儿子去帮助别的点的点
我们可以先处理出1的那些亲儿子需要军队以及还有那些军队可以去支援
把他们按需要时间/剩余时间排序之后对应地去处理
当然如果一只军队在处理到自己的时候 如果他属的那个点需要军队支援的话 我们肯定优先支援自己所属的
因为如果他不支援自己的那么必然后面需要点来支援他 但是后面的点的剩余时间一点比他多 那肯定没有支援自己来的优qwq
#include<cstdio> #include<cstring> #include<algorithm> #define LL long long using std::max; using std::sort; const int M=2e5+7; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } LL l,r,h[M],mark[M]; int n,m,stk[M],top; int first[M],cnt; struct pos{int to,next;LL w;}e[2*M]; void ins(int a,int b,LL w){e[++cnt]=(pos){b,first[a],w}; first[a]=cnt;} void insert(int a,int b,LL w){ins(a,b,w); ins(b,a,w);} int vis[M],q[M],ql,qr,dis[M],fa[M]; void dfs(int x){ int sum=0,h=0; for(int i=first[x];i;i=e[i].next){ int now=e[i].to; if(now==fa[x]) continue; h++; dfs(now); if(!mark[now]) sum++; } if(!sum&&h) mark[x]=1; } int wh[M],cnt1,cnt2;; struct Q{int id;LL w;}q1[M],q2[M]; bool cmp(Q a,Q b){return a.w<b.w;} bool check(LL k){ //printf("[%lld]\n",k); memset(vis,0,sizeof(vis)); memset(mark,0,sizeof(mark)); memset(h,0,sizeof(h)); for(int i=1;i<=top;i++)if(dis[stk[i]]>=k) mark[stk[i]]=1,h[stk[i]]=k; for(int x=n;x;x--){ vis[x]=1; for(int i=first[x];i;i=e[i].next){ int now=e[i].to; if(vis[now]||h[x]<e[i].w) continue; mark[now]=1; h[now]=max(h[now],h[x]-e[i].w); } } //for(int i=1;i<=n;i++) printf("%lld ",mark[i]); puts(""); dfs(1); //for(int i=first[1];i;i=e[i].next) printf("[%d %lld]\n",e[i].to,mark[e[i].to]);puts(""); cnt1=0; cnt2=0; for(int i=first[1];i;i=e[i].next) if(!mark[e[i].to]) q1[++cnt1]=(Q){e[i].to,e[i].w}; for(int i=1;i<=top;i++)if(dis[stk[i]]<k) q2[++cnt2]=(Q){wh[stk[i]],k-dis[stk[i]]}; //printf("[%d %d]\n",cnt1,cnt2); if(!cnt1) return 1; if(cnt2<cnt1) return 0; sort(q1+1,q1+1+cnt1,cmp); sort(q2+1,q2+1+cnt2,cmp); //for(int i=1;i<=cnt1;i++) printf("[%d %lld]\n",q1[i].id,q1[i].w);puts(""); //for(int i=1;i<=cnt2;i++) printf("[%d %lld]\n",q2[i].id,q2[i].w);puts(""); int now=1; for(int i=1;i<=cnt2;i++){ if(!mark[q2[i].id]){mark[q2[i].id]=1;continue;} while(mark[q1[now].id]&&now<=cnt1) now++; if(now==cnt1+1) return 1; if(q2[i].w>=q1[now].w){mark[q1[now].id]=1; now++; continue;} } while(mark[q1[now].id]&&now<=cnt1) now++; if(now==cnt1+1) return 1; //puts(""); return 0; } void bfs(){ ql=qr=1; vis[1]=1; q[ql]=1; ql++; for(int i=first[1];i;i=e[i].next){ int now=e[i].to; if(vis[now]) continue; fa[now]=1; dis[now]=e[i].w; q[++qr]=now; vis[now]=1; wh[now]=now; } while(ql<=qr){ int x=q[ql++]; for(int i=first[x];i;i=e[i].next){ int now=e[i].to; if(vis[now]) continue; fa[now]=x; wh[now]=wh[x]; dis[now]=dis[x]+e[i].w; q[++qr]=now; vis[now]=1; } } } int main(){ int x,y,w,mx; n=read(); for(int i=1;i<n;i++) x=read(),y=read(),w=read(),insert(x,y,w),r+=w; m=read(); for(int i=1;i<=m;i++) x=read(),stk[++top]=x; bfs(); //for(int i=1;i<=n;i++) printf("[%d %d %d]\n",fa[i],wh[i],dis[i]); mx=r; while(l<r){ LL mid=(l+r)>>1; if(check(mid)) r=mid; else l=mid+1; } if(l==mx) printf("-1\n"); else printf("%lld\n",r); return 0; }