题目:https://www.luogu.org/problemnew/show/P1084

5个月前曾经写过一次,某个上学日的深夜,精疲力竭后只有区区10分,从此没管...

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
using namespace std;
priority_queue< pair<int,int> >q1,q2;
int const MAXN=;
int n,m,head[MAXN],ct,ans,fa[MAXN],sid[MAXN],lf,lef[MAXN],gr[MAXN];
ll l,r;
bool vis[MAXN],in[MAXN];
struct N{
int to,next,w;
N(int t=,int n=,int w=):to(t),next(n),w(w) {}
}edge[MAXN<<];
struct E{
int st,pos;
ll rest;
}am[MAXN];
void add(int x,int y,int z)
{
edge[++ct]=N(y,head[x],z);head[x]=ct;
edge[++ct]=N(x,head[y],z);head[y]=ct;
}
void ps(int x)
{
int nw=am[x].st;
while(fa[nw]!=&&am[x].rest-sid[nw])
{
am[x].rest-=sid[nw];
nw=fa[nw];
}
if(fa[nw]==&&am[x].rest>=*sid[nw])am[x].pos=,am[x].rest-=sid[nw];
else am[x].pos=nw;
}
void init(int x,int f,int g,int w)//fa,gr,lef,sid
{
int t=;
fa[x]=f;sid[x]=w;
if(g==)gr[x]=x;
else gr[x]=g;
for(int i=head[x],u;i;i=edge[i].next)
{
u=edge[i].to;
if(u==f)continue;
init(u,x,gr[x],edge[i].w);t++;
}
if(!t)lef[++lf]=x;
}
void dfs(int x)
{
vis[x]=;
for(int i=head[x],u;i;i=edge[i].next)
if(edge[i].to!=fa[x])dfs(edge[i].to);
}
bool pd(ll mid)
{
// printf("mid=%d\n",mid);
memset(vis,,sizeof vis);
memset(in,,sizeof in);
while(q1.size())q1.pop();
while(q2.size())q2.pop();
for(int i=;i<=m;i++)
{
am[i].rest=mid;
ps(i);
if(am[i].pos!=)dfs(am[i].pos);
q1.push(make_pair(-am[i].rest,i));
}
// for(int i=1;i<=m;i++)
// printf("am[%d].pos=%d\n",i,am[i].pos);
for(int i=;i<=lf;i++)
if(!vis[lef[i]]&&!in[gr[lef[i]]])
{
q2.push(make_pair(-sid[gr[lef[i]]],gr[lef[i]]));
in[gr[lef[i]]]=;
}
// printf("q1:%d q2:%d\n",q1.size(),q2.size());
while(q1.size()&&q2.size())
{
int x=q1.top().second;q1.pop();//am
int y=q2.top().second;q2.pop();//gr
// printf("x=%d y=%d\n",x,y);
while(am[x].rest<sid[gr[y]]&&q1.size())x=q1.top().second,q1.pop();
if(am[x].rest<sid[gr[y]]&&!q1.size())return ;
} if(q2.size())return ;
else return ;
}
int main()
{
scanf("%d",&n);
for(int i=,x,y,z;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);r+=z;
}
init(,,,);
// for(int i=1;i<=lf;i++)
// printf("lef[%d]=%d\n",i,lef[i]);
scanf("%d",&m);
for(int i=;i<=m;i++)
scanf("%d",&am[i].st);
ans=-;
while(l<=r)
{
ll mid=((l+r)>>);
// cout<<ans<<endl;
if(pd(mid))ans=mid,r=mid-;
else l=mid+;
}
printf("%d",ans);
return ;
}

囧1

这几天又重新写它了,自信码力已和当时不可同日而语,于是又写了一遍,然而仅仅20分,改了改成了30分...

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
int const xn=;
int n,m,cnt,hd[xn],ct,to[xn<<],nxt[xn<<],w[xn<<],rs[xn],lf[xn],rk[xn];
int f[xn][],son[xn],dep[xn],num[xn];
ll dis[xn],sum,ans;
bool vis[xn],use[xn];
priority_queue<int>q;
vector<int>v[xn];
struct N{
int st,pos; ll tim;
bool operator < (const N &y) const
{return tim<y.tim;}
}a[xn];
int rd()
{
int ret=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=; ch=getchar();}
while(ch>=''&&ch<='')ret=(ret<<)+(ret<<)+ch-'',ch=getchar();
return f?ret:-ret;
}
void add(int x,int y,int z){to[++ct]=y; nxt[ct]=hd[x]; w[ct]=z; hd[x]=ct;}
int dfs(int x,int fa,int r)
{
int ret=,fl=; f[x][]=fa;
for(int i=;i<=;i++)f[x][i]=f[f[x][i-]][i-];
for(int i=hd[x],u;i;i=nxt[i])
{
if((u=to[i])==fa)continue;
fl=;
dis[u]=dis[x]+w[i]; dep[u]=dep[x]+;
if(x==)lf[u]+=dfs(u,x,u),son[++cnt]=u;
else ret+=dfs(u,x,r);
}
if(!fl)ret=,rs[x]=r;
return ret;
}
bool cmp(int a,int b){return dis[son[a]]>dis[son[b]];}
void dfs2(int x)
{
bool fl=;
for(int i=hd[x],u;i;i=nxt[i])
if((u=to[i])!=f[x][])fl=,dfs2(u);
if(!fl)num[rs[x]]++;
}
bool ck(int mid)
{
memset(vis,,sizeof vis);
memset(num,,sizeof num);
memset(use,,sizeof use);
for(int i=;i<=cnt;i++)v[i].clear();
while(q.size())q.pop();
for(int i=;i<=m;i++)a[i].pos=;
for(int i=;i<=m;i++)
{
int x=a[i].st; ll ret=mid;
for(int j=;j>=;j--)
if(f[x][j]>&&dis[x]-dis[f[x][j]]<=ret)
ret-=dis[x]-dis[f[x][j]],x=f[x][j];
if(dep[x]>||(dep[x]==&&ret<dis[x]))dfs2(x);
else
{
a[i].pos=x; a[i].tim=ret-dis[x];
q.push(i); //x:1~n
v[x].push_back(i);
// printf("in:%d\n",i);//tim从大到小
}
}
for(int i=;i<=cnt;i++)
if(num[son[i]]==lf[son[i]])vis[i]=;//i != son[i] // vis[1~cnt]
for(int i=;i<=cnt;i++)
{
int x=rk[i];//1~cnt
// printf("vis[%d]=%d\n",son[x],vis[x]);
if(vis[x])continue;
if(!q.size())return ;
int k=q.top(); q.pop();
while(use[k])k=q.top(),q.pop();
if(a[k].tim<dis[son[x]])
{
int us=-;
for(int j=;j<v[son[x]].size();j++)
{
int nw=v[son[x]][j];
if(!use[nw]&&(us==-||a[nw].tim<a[us].tim))us=nw;
}
if(us==-)return ;
else use[us]=,q.push(k);
}
vis[x]=;
// printf("%d -> %d\n",i,son[x]);
}
// printf("return 1\n");
return ;
}
int main()
{
n=rd();
for(int i=,x,y,z;i<n;i++)
{
x=rd(); y=rd(); z=rd();
add(x,y,z); add(y,x,z);
sum+=z;
}
m=rd();
for(int i=;i<=m;i++)a[i].st=rd();
dfs(,,);
for(int i=;i<=cnt;i++)rk[i]=i;
sort(rk+,rk+cnt+,cmp);//rk -> 1~cnt
// for(int i=1;i<=cnt;i++)printf("dis[%d]=%lld rk[%d]=%d\n",son[i],dis[son[i]],i,rk[i]);
ll l=,r=sum; ans=-;
while(l<=r)
{
ll mid=((l+r)>>1ll);
// printf("l=%lld r=%lld mid=%lld\n",l,r,mid);
if(ck(mid))ans=mid,r=mid-;
else l=mid+;
}
printf("%lld\n",ans);
return ;
}

囧2

然后又去参考了TJ...看到思路和我的一样,但是代码简洁很多...

于是改改改,然后和模仿的那篇TJ拍拍拍,居然拍出了TJ的错...又和另一篇TJ拍拍拍,大数据又有错...

不管了直接交上去,就A了...

然后发现数据生成没管军队不在根上,但第一篇TJ小数据真的错了...

和 Narh 的代码拍,大数据又有错...但是数据那么大怎么改...不管了(反正也A了)...

又练习码力了,没事不要多写什么 queue 啦, vector 啦,直接排个序就好了。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const xn=;
int n,m,hd[xn],ct,to[xn<<],nxt[xn<<],w[xn<<],dis[xn],sum,ans;
int f[xn][],num[xn],mn[xn],cnta,cnts,st[xn];
bool vis[xn],use[xn];
struct N{
int id,tim;
bool operator < (const N &y) const
{return tim>y.tim;}
}a[xn],son[xn];
int rd()
{
int ret=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=; ch=getchar();}
while(ch>=''&&ch<='')ret=(ret<<)+(ret<<)+ch-'',ch=getchar();
return f?ret:-ret;
}
void add(int x,int y,int z){to[++ct]=y; nxt[ct]=hd[x]; w[ct]=z; hd[x]=ct;}
void dfs(int x,int fa,int r)
{
int ret=; f[x][]=fa;
for(int i=;i<=;i++)f[x][i]=f[f[x][i-]][i-];
for(int i=hd[x],u;i;i=nxt[i])
{
if((u=to[i])==fa)continue;
dis[u]=dis[x]+w[i]; dfs(u,x,r);
}
}
bool dfs2(int x)
{
bool fl=,bj=;
if(vis[x])return ;
for(int i=hd[x],u;i;i=nxt[i])
{
if((u=to[i])==f[x][])continue; bj=;
bool k=dfs2(u);
if(!k)
{
fl=;
if(x==)son[++cnts].id=u,son[cnts].tim=dis[u];
}
}
if(bj)return ;
return fl;
}
bool ck(int mid)
{
memset(vis,,sizeof vis);
memset(use,,sizeof use);
memset(mn,,sizeof mn);
cnta=; cnts=;
for(int i=;i<=m;i++)
{
int x=st[i]; ll ret=mid;
for(int j=;j>=;j--)
if(f[x][j]>&&dis[x]-dis[f[x][j]]<=ret)
ret-=dis[x]-dis[f[x][j]],x=f[x][j];
if(f[x][]>||(f[x][]==&&ret<dis[x]))vis[x]=;
else
{
a[++cnta].id=i; a[cnta].tim=ret-dis[x];//-dis[x]
if(!mn[x]||a[cnta].tim<a[mn[x]].tim)mn[x]=i;//mn[1~n]=(1~m)
}
}
if(dfs2())return ;
sort(a+,a+cnta+); sort(son+,son+cnts+);
for(int i=,p=;i<=cnts;i++)
{
int nw=son[i].id;
if(mn[nw]&&!use[mn[nw]]){use[mn[nw]]=; continue;}//优先用小的,不用考虑其它儿子是因为从大往小用
while(p<=cnta&&use[a[p].id])p++;
if(p>cnta||a[p].tim<son[i].tim)return ;
use[a[p].id]=;
}
return ;
}
int main()
{
n=rd();
for(int i=,x,y,z;i<n;i++)
{
x=rd(); y=rd(); z=rd();
add(x,y,z); add(y,x,z);
sum+=z;
}
m=rd();
for(int i=;i<=m;i++)st[i]=rd();
dfs(,,);
int l=,r=sum; ans=-;
while(l<=r)
{
int mid=((l+r)>>1ll);
if(ck(mid))ans=mid,r=mid-;
else l=mid+;
}
printf("%d\n",ans);
return ;
}

洛谷 P1084 疫情控制 —— 二分+码力的更多相关文章

  1. 洛谷P1084 疫情控制(NOIP2012)(二分答案,贪心,树形DP)

    洛谷题目传送门 费了几个小时杠掉此题,如果不是那水水的数据的话,跟列队的难度真的是有得一比... 话说蒟蒻仔细翻了所有的题解,发现巨佬写的都是倍增,复杂度是\(O(n\log n\log nw)\)的 ...

  2. 洛谷P1084 疫情控制 [noip2012] 贪心+树论+二分答案 (还有个小bugQAQ

    正解:贪心+倍增+二分答案 解题报告: 正好想做noip的题目然后又想落实学长之前讲的题?于是就找上了这题 其实之前做过,70,然后实在细节太多太复杂就不了了之,现在再看一遍感觉又一脸懵了... 从标 ...

  3. 2018.09.26洛谷P1084 疫情控制(二分+倍增)

    传送门 好题啊. 题目要求的最大值最小,看到这里自然想到要二分答案. 关键在于怎么检验. 显然对于每个点向根走比向叶节点更优. 因此我们二分答案之后,用倍增将每个点都向上跳到跳不动为止. 这时我们ch ...

  4. [NOIP2012] 提高组 洛谷P1084 疫情控制

    题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都, 也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散 ...

  5. NOIP2012 洛谷P1084 疫情控制

    Description: H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控制疫情 ...

  6. 洛谷P1084 疫情控制(贪心+倍增)

    这个题以前写过一遍,现在再来写,感觉以前感觉特别不好写的细节现在好些多了,还是有进步吧. 这个题的核心思想就是贪心+二分.因为要求最小时间,直接来求问题将会变得十分麻烦,但是如果转换为二分答案来判断可 ...

  7. 洛谷P1084 疫情控制

    题目 细节比较多的二分+跟LCA倍增差不多的思想 首先有这样一个贪心思路,深度越低的检查点越好,而最长时间和深度具有单调性,即给定时间越长,每个军队能向更浅的地方放置检查点.因此可以考虑二分时间,然后 ...

  8. Luogu P1084 疫情控制 | 二分答案 贪心

    题目链接 观察题目,答案明显具有单调性. 因为如果用$x$小时能够控制疫情,那么用$(x+1)$小时也一定能控制疫情. 由此想到二分答案,将问题转换为判断用$x$小时是否能控制疫情. 对于那些在$x$ ...

  9. luogu P1084疫情控制 二分

    链接 loj luogu太水不要去了. 思路 二分. 每个军队在一定的时间内越往上越好. 注意一个军队可以跨过1去帮别的. 把能到1脚下的点都存下来特判. 有一种情况是这个子树内只有一个军队,但这个军 ...

随机推荐

  1. 树莓派 -- 输入设备驱动 (key) 续2: 转载 Setting up a GPIO-Button “keyboard” on a Raspberry Pi

    使用device-tree (DT) overlay应该是更方便的方法: http://blog.gegg.us/2017/01/setting-up-a-gpio-button-keyboard-o ...

  2. 源码学习-String类

    最近在扫描CodeDex时报了一个不能使用String.intern()的字符串来做锁对象的告警,对这个问题有疑问查了些资料,顺便学习一下String类的源码. 1.类定义 String 被final ...

  3. Python之模块和包导入

    Python之模块和包导入 模块导入: 1.创建名称空间,用来存放模块XX.py中定义的名字 2.基于创建的名称空间来执行XX.py. 3.创建名字XX.py指向该名称空间,XX.名字的操作,都是以X ...

  4. Python之模块和包的创建与使用

    一.模块的概念 在计算机的开发过程中,随着程序代码越写越多,在一个文件里代码就越来越长,越来越不容易维护. 为了编写可维护的代码,我们把很多函数分组,放在不同的文件里面,这样,每个文件包含的代码就相对 ...

  5. HDU 4747 Mex【线段树上二分+扫描线】

    [题意概述] 一个区间的Mex为这个区间没有出现过的最小自然数,现在给你一个序列,要求求出所有区间的Mex的和. [题解] 扫描线+线段树. 我们在线段树上维护从当前左端点开始的前缀Mex,显然从左到 ...

  6. Linux学习总结(22)——CentOS7.2安装Nginx

    一.使用Yum安装(推荐) 使用Yum安装是推荐的方式,整体的流程非常的简单,也不容易出错,如果不需要什么特殊配置,建议使用Yum尽进行安装. 1.安装epel-release源并进行安装 1 2 3 ...

  7. js用for...in 这种遍历的方式

    var arr = new Array("first", "second", "third") for(var item in arr) { ...

  8. JavaEE JDBC PreparedStatement

    PreparedStatement @author ixenos PreparedStatement工作原理 注意:虽然mysql不支持PreparedStatement优化,但依然有预编译的实现! ...

  9. Android BGABadgeView:新消息/未接来电/未读消息/新通知圆球红点提示(1)

     Android BGABadgeView:新消息/未接来电/未读消息/新通知圆球红点提示(1) 现在很多的APP会有新消息/未接来电/未读消息/新通知圆球红点提示,典型的以微信.QQ新消息提示为 ...

  10. 如何探测浏览器是否开启js功能

    <body> ... ... <script type="text/javascript"> <!-- document.write("He ...