luogu1084【2012提高】疫情控制(二分答案+贪心+倍增)
来源:互联网 发布:网络百家家乐是真的吗 编辑:程序博客网 时间:2024/06/05 00:55
这题可真是厉害死了。。。调了一天。。。
别看我D2T2考了二分答案,D2T3也是二分答案哟!!惊不惊喜!意不意外!什么?你说我考过贪心和倍增了??那是不是更惊喜啦!更意外啦!
求最小的调动时间,显然调动时间越大,越可能满足条件。所以我们二分这个答案,把原问题变为给定调动时间,判断可行性的问题。显然,一支军队越往跟走能覆盖的边境越多。我们根据调动时间可以把原军队分成两类:(用树上倍增快速实现)
1、到不了根的,那就尽量的往根走,显然这样最优。
2、能到跟的,那就都先到根等着,并算出到跟后的剩余时间。
对于那些没到跟的,他们已经是最优的了,一遍dfs记录哪些点已经被覆盖了(一个点被覆盖,当且仅当他的所有儿子被覆盖)。我们现在只关心根的儿子们,我们要调动那些还有剩余时间的军队来覆盖那些没有被覆盖的儿子们。怎么分配军队呢?我们只好贪心地分配。把那些到根的军队按剩余时间从小到大排序,记作q数组,把那些需要被覆盖的根的儿子按到根的距离从小到大排序,记作b数组。我们贪心地让剩余时间小的去覆盖需要时间小的。但还有个细节,如果一支军队是从a这个儿子上来的,到了根,但剩余时间不足以再回到a了,我们让他直接留在a就好了,这样肯定更优,可以证明的:
如果这只军队去了别的地方x点,然后y军队来填补a,由已知得d(a)>d(x)显然让y去x,这支军队驻扎在A更好。
#include <bits/stdc++.h>using namespace std;#define ll long long#define inf 0x3f3f3f3f#define pa pair<ll,int>#define N 50010inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x*f;}int n,m,h[N],num=0,a[N],fa[N][18],son[N],Log[N],bel[N];ll d[N][18],l=0,r=500000,ans=0;bool mark[N],used[N];struct edge{ int to,next,val;}data[N<<1];void dfs(int x,int tp){ bel[x]=tp; for(int i=h[x];i;i=data[i].next){ int y=data[i].to;if(y==fa[x][0]) continue; fa[y][0]=x;d[y][0]=data[i].val;dfs(y,tp); }}void dfs1(int x){ bool flag=1,fson=0; for(int i=h[x];i;i=data[i].next){ int y=data[i].to;if(y==fa[x][0]) continue;fson=1; dfs1(y);if(!mark[y]) flag=0; } if(fson&&flag) mark[x]=1;}bool jud(ll tot){ memset(mark,0,sizeof(mark));memset(used,0,sizeof(used)); vector<pa>q;vector<pa>b; for(int i=1;i<=m;++i){ int x=a[i];ll dx=0; for(int j=Log[n];j>=0;--j) if(fa[x][j]&&dx+d[x][j]<=tot) dx+=d[x][j],x=fa[x][j]; if(x!=1) mark[x]=1; else q.push_back(make_pair(tot-dx,bel[a[i]])); }dfs1(1);if(mark[1]) return 1; for(int i=1;i<=son[0];++i){ int y=son[i];if(mark[y]) continue; b.push_back(make_pair(d[y][0],y)); }sort(b.begin(),b.end());sort(q.begin(),q.end()); for(int i=0;i<q.size();++i){//到了根以后的剩余时间不够再回来,那干脆就别去根了 int x=q[i].second; if(!mark[x]&&q[i].first<d[x][0]) mark[x]=1,used[i]=1; }int pq=0,pb=0; while(pq<q.size()&&pb<b.size()){//贪心地分配军队 if(used[pq]){pq++;continue;} if(mark[b[pb].second]){pb++;continue;} if(q[pq].first<b[pb].first) pq++; else pq++,pb++; }while(pb<b.size()&&mark[b[pb].second]) pb++; if(pb==b.size()) return 1; else return 0;}int main(){// freopen("blockade4.in","r",stdin); n=read();Log[0]=-1;for(int i=1;i<=n;++i) Log[i]=Log[i>>1]+1; for(int i=1;i<n;++i){ int x=read(),y=read(),val=read(); data[++num].to=y;data[num].next=h[x];h[x]=num;data[num].val=val; data[++num].to=x;data[num].next=h[y];h[y]=num;data[num].val=val; if(x!=1&&y!=1) continue; son[++son[0]]= x==1?y:x; fa[son[son[0]]][0]=1;d[son[son[0]]][0]=val; }m=read();if(son[0]>m){puts("-1");return 0;} for(int i=1;i<=son[0];++i) dfs(son[i],son[i]); for(int i=1;i<=Log[n];++i) for(int j=1;j<=n;++j) fa[j][i]=fa[fa[j][i-1]][i-1],d[j][i]=d[fa[j][i-1]][i-1]+d[j][i-1]; for(int i=1;i<=m;++i) a[i]=read(); while(l<=r){ ll mid=l+r>>1; if(jud(mid)) r=mid-1,ans=mid; else l=mid+1; } printf("%lld\n",ans); return 0;}
阅读全文
0 0
- luogu1084【2012提高】疫情控制(二分答案+贪心+倍增)
- luogu1084疫情控制-二分+倍增+贪心
- 洛谷P1084:疫情控制 (二分答案+倍增+贪心)
- 洛谷 P1084 疫情控制 (二分答案+倍增+贪心)
- 疫情控制(二分+贪心+倍增)
- code vs 1218 疫情控制 (二分+贪心+倍增)
- [NOIP2012][CODEVS1218]疫情控制(二分+倍增+贪心)
- NOIP2012 疫情控制(二分,倍增,贪心)
- noip2012 疫情控制 (二分+倍增)
- 洛谷1084/codevs1218 二分+倍增+贪心,疫情控制,分步讲解
- [noip2012]疫情控制(二分+贪心)
- noip2012 疫情控制 图论+贪心+二分
- 【NOIP2012提高组】疫情控制
- 【NOIP2012提高组】疫情控制
- NOIP 2012 疫情控制
- NOIP 2012 疫情控制
- [NOIP] [LCA] [贪心] NOIP2012Day2 疫情控制(blockade)
- JZOJ 3104【NOIP2012提高组】疫情控制
- OpenCV编程->图像边界拓展copyMakeBorder
- Android设计模式之简单工厂模式(一)
- S3C2440看门狗定时器(Watchdog)
- 《Java编程思想》读书笔记
- 17高软实验二报告
- luogu1084【2012提高】疫情控制(二分答案+贪心+倍增)
- JavaScript中 call 与 apply、bind 的使用
- org.apache.commons.lang3.StringUtils,UUID和LoadingCache
- [NOIP2017模拟]跳高
- 算法进阶之贪心算法
- JAVA学习笔记(6)--String的常用方法
- 整合JavaWeb面试过程中相关问题
- iOS 中APP被拒以及解决办法总结<待更新>
- 如何阻止button默认的刷新页面操作