P1084 [NOIP2012 提高组] 疫情控制 (二分答案、贪心)
因为若一个时间限制满足题意,则所有比它大的时间限制一定都满足题意,因此本题答案具有单调性,可以想到二分答案求解。
本题思路不是很难,但细节和代码实现比较复杂。
见牛人博客:https://www.luogu.com.cn/blog/TEoS/p1084-yi-qing-kong-zhi
1 #include<bits/stdc++.h> 2 typedef long long ll; 3 using namespace std; 4 const int N=6e4; 5 int n,m,t,tot,atot,btot,ctot; 6 int d[N],query[N],f[N][20]; 7 int to[N<<1],edge[N<<1],nxt[N<<1],head[N]; 8 bool ok,sta[N],need[N]; 9 ll ans,tim[N],ned[N],dist[N][20]; 10 pair<ll,int> h[N]; 11 queue<int> q; 12 void add(int x,int y,int z){ 13 nxt[++tot]=head[x];head[x]=tot;to[tot]=y;edge[tot]=z; 14 } 15 16 void bfs(){ 17 q.push(1);d[1]=1; 18 while(q.size()){ 19 int x=q.front();q.pop(); 20 for(int i=head[x];i;i=nxt[i]){ 21 int y=to[i]; 22 if(d[y]) continue; 23 d[y]=d[x]+1; 24 f[y][0]=x;dist[y][0]=edge[i]; 25 for(int j=1;j<=t;j++){ 26 f[y][j]=f[f[y][j-1]][j-1]; 27 dist[y][j]=dist[y][j-1]+dist[f[y][j-1]][j-1]; 28 } 29 q.push(y); 30 } 31 } 32 } 33 34 void init(){ 35 memset(sta,0,sizeof(sta)); 36 memset(tim,0,sizeof(tim)); 37 memset(ned,0,sizeof(ned)); 38 memset(h,0,sizeof(h)); 39 memset(need,0,sizeof(need)); 40 atot=0,btot=0,ctot=0; 41 } 42 43 bool dfs(int x){ 44 bool pson=0; 45 if(sta[x]) return 1; 46 for(int i=head[x];i;i=nxt[i]){ 47 int y=to[i]; 48 if(d[y]<d[x]) continue; 49 pson=1; 50 if(!dfs(y)) return 0; 51 } 52 if(!pson) return 0; 53 return 1; 54 }//如果是叶子结点,pson=0,那么该路径没有军队驻扎 55 56 bool ck(ll lim){ 57 for(int i=1;i<=m;i++){//上移军队并处理闲置军队 58 ll x=query[i],cnt=0; 59 for(int j=t;j>=0;j--) 60 if(f[x][j]>1/*不能是根节点*/ && cnt+dist[x][j]<=lim){ 61 cnt+=dist[x][j]; 62 x=f[x][j]; 63 } 64 if(f[x][0]==1 && cnt+dist[x][0]<=lim) 65 h[++ctot]=make_pair(lim-cnt-dist[x][0],x); 66 else sta[x]=1; 67 } 68 for(int i=head[1];i;i=nxt[i]) 69 if(!dfs(to[i])) need[to[i]]=1;//dfs寻找路径未被驻扎的叶子节点 70 sort(h+1,h+ctot+1);//第一关键字排序 71 for(int i=1;i<=ctot;i++) 72 if(need[h[i].second] && h[i].first<dist[h[i].second][0]) 73 need[h[i].second]=0; 74 else tim[++atot]=h[i].first;//对根节点的需要被驻扎的子节点进行初步处理 75 for(int i=head[1];i;i=nxt[i]) 76 if(need[to[i]]) ned[++btot]=dist[to[i]][0];//找到仍需要被驻扎的节点并存储 77 if(atot<btot) return 0;//无解 78 sort(ned+1,ned+btot+1); 79 int i=1,j=1; 80 while(i<=btot && j<=atot)//双指针扫描 81 if(tim[j]>=ned[i]) i++,j++; 82 else j++; 83 if(i>btot) return 1; 84 return 0; 85 } 86 87 int main(){ 88 cin>>n;ll l=0,r=0,mid; 89 t=log2(n)+1; 90 for(int i=1;i<n;i++){ 91 int x,y,z;scanf("%d%d%d",&x,&y,&z); 92 add(x,y,z);add(y,x,z);r+=z; 93 } 94 bfs();//树上倍增预处理 95 cin>>m;for(int i=1;i<=m;i++) scanf("%d",&query[i]);//存每个军队 96 while(l<=r){//二分答案 97 init();mid=(l+r)>>1; 98 if(ck(mid)) r=mid-1,ans=mid,ok=1; 99 else l=mid+1; 100 } 101 if(!ok) cout<<-1<<endl; 102 else cout<<ans<<endl; 103 return 0; 104 }
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!