洛谷P3006 [USACO11JAN]瓶颈Bottleneck(堆模拟)
传送门
感觉这题的思路还是挺不错的。然而为啥全网就一个题解而且只有代码……然后我只好看着代码理解了好久……
题意就是有一棵树,每一个节点向他父亲节点连边,且有一个容量表示每一秒可以经过的牛的数量,每一个点有一堆牛,在满足容量限制的情况下可以不断往祖先跳直到跳到1节点。然后问你在保证总时间最短的情况下第$t$秒1节点有多少头牛
首先,不难发现一个贪心,就是如果向父亲的边能够流满的时候,流满一定比不流满优
那么我们令每一条边都强制流满,然后对每个点记录一个值$pass[i]$,值为它能向父亲流的最大的流量减去它的儿子们向它流的最大流量,不难发现它代表如果每条边都流满之后每秒能有多少头牛离开这个点向祖先去。
那么我们设每一个节点开始时牛的个数为$cow[i]$,那么,$cow[i]/pass[i]$就代表这一个节点的所有牛都走光所需要的时间
那么令$t=cow[i]/pass[i]$,当时间小于等于$t$的时候,我们需要考虑这一个点还剩下多少头牛。当时间大于$t$的时候,我们已经不需要再考虑这个点还剩下多少头牛了,因为可以在满流之后让它所有的牛都到它的父亲那里去。那么,我们可以把它和它的父亲看做同一个点,牛的数量为两个点之和,$pass[fa[i]]$也是两个点之和(它和父亲之间的那条边的流量因为父亲减一次它加一次已经抵消了),然后再对这个点记录一个新的$t$就好了。这个可以用一个并查集维护
那么,我们对询问按时间排序。当询问的时间大于当前$t$的时候,我们把所有$t$小于等于询问的时间的点全都和它的父亲给并起来。当询问的时间小于等于当前$t$时,答案就是$cow[1]+pass[1]*询问的时间$($cow[1]$代表所有已经被缩到这一个点的总的牛的数量,然后1点的pass肯定是负数,所以减去就相当于加上这个点的儿子的点全都满流向它流,在询问的这段时间里能流多少)
然后总不可能维护时间轴……所以开个优先队列把所有点的$t$给扔进去就好了,反正就这些点的$t$有用
讲的应该还蛮清楚的吧……
1 // luogu-judger-enable-o2 2 //minamoto 3 #include<iostream> 4 #include<cstdio> 5 #include<cstring> 6 #include<algorithm> 7 #include<queue> 8 #define ll long long 9 using namespace std; 10 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 11 char buf[1<<21],*p1=buf,*p2=buf; 12 inline ll read(){ 13 #define num ch-'0' 14 char ch;bool flag=0;ll res; 15 while(!isdigit(ch=getc())) 16 (ch=='-')&&(flag=true); 17 for(res=num;isdigit(ch=getc());res=res*10+num); 18 (flag)&&(res=-res); 19 #undef num 20 return res; 21 } 22 char sr[1<<21],z[20];int C=-1,Z; 23 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} 24 inline void print(ll x){ 25 if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; 26 while(z[++Z]=x%10+48,x/=10); 27 while(sr[++C]=z[Z],--Z);sr[++C]='\n'; 28 } 29 const int N=100005; 30 struct query{ll t,res;int id;}ask[N]; 31 inline bool cmp1(query x,query y){return x.t<y.t;} 32 inline bool cmp2(query x,query y){return x.id<y.id;} 33 struct node{ 34 ll t;int x;node(){} 35 node(ll t,int x):t(t),x(x){} 36 inline bool operator <(const node &b)const 37 {return t>b.t;} 38 }; 39 priority_queue<node> q; 40 int fa[N],f[N],lim[N];ll cow[N],pass[N]; 41 int find(int x){ 42 return fa[x]==x?x:fa[x]=find(fa[x]); 43 } 44 int n,m; 45 int main(){ 46 // freopen("testdata.in","r",stdin); 47 n=read(),m=read(); 48 for(int i=1;i<=n;++i) fa[i]=i; 49 for(int i=2;i<=n;++i) 50 f[i]=read(),cow[i]=read(),lim[i]=read(),pass[f[i]]-=lim[i],pass[i]+=lim[i]; 51 for(int i=1;i<=m;++i) 52 ask[i].t=read(),ask[i].id=i; 53 sort(ask+1,ask+1+m,cmp1); 54 for(int i=2;i<=n;++i) 55 if(pass[i]>0) 56 q.push(node(cow[i]/pass[i],i)); 57 int l=1,x,tp; 58 while(!q.empty()&&l<=m){ 59 while(l<=m&&ask[l].t<=q.top().t) 60 ask[l].res=cow[1]-pass[1]*ask[l].t,++l; 61 if(fa[q.top().x]!=q.top().x){q.pop();continue;} 62 x=q.top().x,tp=find(f[x]),cow[tp]+=cow[x]; 63 pass[tp]+=pass[x],fa[x]=tp; 64 if(pass[tp]>0) q.push(node(cow[tp]/pass[tp],tp)); 65 q.pop(); 66 } 67 sort(ask+1,ask+1+m,cmp2); 68 for(int i=1;i<=m;++i) print(ask[i].res); 69 Ot(); 70 return 0; 71 }
转载于:https://www.cnblogs.com/bztMinamoto/p/9622691.html
洛谷P3006 [USACO11JAN]瓶颈Bottleneck(堆模拟)相关推荐
- 洛谷 P3378 【模板】堆
2019-05-30 题目 : 洛谷 P3378 [模板]堆 : https://www.luogu.org/problemnew/show/P3378 题目描述 如题,初始小根堆为空,我们需要支持以 ...
- 洛谷P2085ssl1411OJ1370-最小函数值【堆,贪心】
前言 有一个东西卡了我一会 折叠N*或N+ 正整数集 (由全体正整数组成的集合) N*:={1,2,3,-,n,-} 题目 洛谷P2085 OJ1370 给出n个ai,bi,ci.定义一个函数 fi( ...
- 洛谷:P2832 行路难(堆优化Dijkstra(错解)bfs(正解) + 记录路径)
洛谷:P2832 行路难 写这道题确实是行路难- 此题的最短路约束不只是边权,还有边数(每经过一条边,之后经过的边权值都 +1+1+1 ) 从期望的角度分析,我们肯定是想 尽可能走的路程越短,走得路径 ...
- 洛谷 P1031 均分纸牌【交叉模拟】
题目描述 有 N 堆纸牌,编号分别为 1,2,-, N.每堆上有若干张,但纸牌总数必为 N 的倍数.可以在任一堆上取若干张纸牌,然后移动. 移牌规则为:在编号为 1 堆上取的纸牌,只能移到编号为 2 ...
- 洛谷 P1598 垂直柱状图【字符串+模拟】
P1598 垂直柱状图 题目描述 写一个程序从输入文件中去读取四行大写字母(全都是大写的,每行不超过72个字符),然后用柱状图输出每个字符在输入文件中出现的次数.严格地按照输出样例来安排你的输出格式. ...
- 洛谷 P1055 ISBN号码【字符串+模拟】
P1055 ISBN号码 题目描述 每一本正式出版的图书都有一个ISBN号码与之对应,ISBN码包括9位数字.1位识别码和3位分隔符,其规定格式如"x-xxx-xxxxx-x",其 ...
- 洛谷 P3378 【模板】堆
嗯... 这是一道堆的模板题,但我个人感觉最好的做法就是通过优先队列来进行操作... 首先我们看一下这道水题.... 题目描述 如题,初始小根堆为空,我们需要支持以下3种操作: 操作1: 1 x 表示 ...
- 洛谷 - P1308 统计单词数(字符串+模拟)
题目链接:点击查看 题目大意:给出一个字符串a和字符串b,现在问字符串b中有多少个单词与字符串a相等,并记录第一次出现的位置 题目分析:看似很简单的一个模拟题,其实包含了不少需要注意的地方: stri ...
- 洛谷P3378 【模板】堆
题目描述 如题,初始小根堆为空,我们需要支持以下3种操作: 操作1: 1 x 表示将x插入到堆中 操作2: 2 输出该小根堆内的最小数 操作3: 3 删除该小根堆内的最小数 输入输出格式 输入格式: ...
最新文章
- vector大小为1,如果直接输出它-2,为何不是-1?
- JNI中java类型的简写
- redisson MultiLock原理及分布式锁的应用
- WebLogic中文博客
- 2020年工作总结大会感悟
- 【Hbase】HBase界面简介
- qq浏览器插件_惊艳与吐槽:QQ浏览器升级到 Chromium70 内核以后
- 米勒机会信托或将通过GBTC投资比特币
- 什么叫做项目孵化_什么叫创业孵化服务?
- 如何确定类型是否使用C#反射实现接口
- Qt之利用事件过滤器在QLabel上画框
- 机器学习(Machine Learning)与深度学习(Deep Learning)资料汇总
- php万年历月份处理_使用 PHP 写的万年历接口
- Mybatis 大于小于符号解决
- 网站被百度提示安全风险拦截后如何快速申请解封
- 手机按键触发事件--隐藏APP到任务后台
- gnuplot常用技巧
- 计算机的职业形象,计算机专业科开展学生干部职业形象塑造专题培训
- 你竟然还不知道电脑上的F1-F12快捷键的作用
- PhoneRescue for Mac(iOS数据恢复软件)