洛谷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(堆模拟)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 二季度全球PC出货量同比下降15% 惠普
- 下一篇: 华为Mate60造型流出 设计更加独特