传送门

感觉这题的思路还是挺不错的。然而为啥全网就一个题解而且只有代码……然后我只好看着代码理解了好久……

题意就是有一棵树,每一个节点向他父亲节点连边,且有一个容量表示每一秒可以经过的牛的数量,每一个点有一堆牛,在满足容量限制的情况下可以不断往祖先跳直到跳到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$有用

讲的应该还蛮清楚的吧……

 // luogu-judger-enable-o2
//minamoto
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[<<],*p1=buf,*p2=buf;
inline ll read(){
#define num ch-'0'
char ch;bool flag=;ll res;
while(!isdigit(ch=getc()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getc());res=res*+num);
(flag)&&(res=-res);
#undef num
return res;
}
char sr[<<],z[];int C=-,Z;
inline void Ot(){fwrite(sr,,C+,stdout),C=-;}
inline void print(ll x){
if(C><<)Ot();if(x<)sr[++C]=,x=-x;
while(z[++Z]=x%+,x/=);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=;
struct query{ll t,res;int id;}ask[N];
inline bool cmp1(query x,query y){return x.t<y.t;}
inline bool cmp2(query x,query y){return x.id<y.id;}
struct node{
ll t;int x;node(){}
node(ll t,int x):t(t),x(x){}
inline bool operator <(const node &b)const
{return t>b.t;}
};
priority_queue<node> q;
int fa[N],f[N],lim[N];ll cow[N],pass[N];
int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
int n,m;
int main(){
// freopen("testdata.in","r",stdin);
n=read(),m=read();
for(int i=;i<=n;++i) fa[i]=i;
for(int i=;i<=n;++i)
f[i]=read(),cow[i]=read(),lim[i]=read(),pass[f[i]]-=lim[i],pass[i]+=lim[i];
for(int i=;i<=m;++i)
ask[i].t=read(),ask[i].id=i;
sort(ask+,ask++m,cmp1);
for(int i=;i<=n;++i)
if(pass[i]>)
q.push(node(cow[i]/pass[i],i));
int l=,x,tp;
while(!q.empty()&&l<=m){
while(l<=m&&ask[l].t<=q.top().t)
ask[l].res=cow[]-pass[]*ask[l].t,++l;
if(fa[q.top().x]!=q.top().x){q.pop();continue;}
x=q.top().x,tp=find(f[x]),cow[tp]+=cow[x];
pass[tp]+=pass[x],fa[x]=tp;
if(pass[tp]>) q.push(node(cow[tp]/pass[tp],tp));
q.pop();
}
sort(ask+,ask++m,cmp2);
for(int i=;i<=m;++i) print(ask[i].res);
Ot();
return ;
}

最新文章

  1. linux定时任务crond export变量问题
  2. Dapper学习笔记(一)
  3. ue4 NewObject/StaticConstructObject_Internal/StaticAllocateObject/FObjectInitializer:对象创建和初始化
  4. Java final类
  5. github and SourceTree初步使用
  6. POJ 3174 Alignment of the Planets (暴力求解)
  7. POJ 3140-Contestants Division(树形dp)
  8. ASP.NET农历时间显示(两)
  9. C#动态编程
  10. word遇到错误 使其无法正常工作 因此需要关闭word 是否希望我们立刻修复
  11. AIO5凭证性质设置接收下/上差(%),但是订单操作不起效。
  12. 高性能缓存系统Memcached在ASP.NET MVC中应用
  13. nginx,作为前端的你会多少?
  14. mysql 时间格式转换
  15. 中兴F660光猫改桥接
  16. python字符编码与文件打开
  17. sqlserver等软件下载
  18. GIL全局解释器锁+GIL全局解释器锁vs互斥锁+定时器+线程queue+进程池与线程池(同步与异步)
  19. da shu mo ban
  20. mysql数据库创建和权限分配

热门文章

  1. 命令行执行大sql文件
  2. 多线程、方便扩展的Windows服务程序框架
  3. Java企业微信开发_13_异常:com.qq.weixin.mp.aes.AesException: 解密后得到的buffer非法
  4. 第一章 走进Python
  5. L99
  6. bzoj 2553: [BeiJing2011]禁忌 AC自动机+矩阵乘法
  7. Kindergarten
  8. C/C++面试题总结(1)
  9. YARN指令
  10. 【转】Ruby on Rails中select使用方法