Loj#6405-「ICPC World Finals 2018」征服世界【模拟费用流,左偏树】

1|0正题

题目链接:https://loj.ac/p/6405


1|1题目大意

给出n个点的一棵树,每个点有xi个军队,需要yi个军队,你可以移动军队,求使得满足所有点要求的情况下,军队移动路径和的最小值。

1n250000,军队总数和不超过106


1|2解题思路

一看就是费用流,但是数据范围很大所有是模拟费用流。

那么考虑贪心,因为我们要贪心所以我们很难强制满流,那么我们就定义一个流量会额外带上一个的权值,然后最后答案加上×c就好了。

那么考虑一个流量从x流到y,费用是depx+depydeplca×2,如果一个是需要军队的,那么定义valx=depx,否则valx=depx

那么就可以视费用为valx+valydeplca×2,那么这些答案我们就可以在lca处维护了,设它们的lcaz

考虑用可并堆储存子树内的valxvaly,然后每次取出最小的直到valx+valydepz×20为止,但是我们还需要一个退流的操作,也就是可撤回的过程。这个过程我们的权值是相反的,定义新的valx=2×depzvaly,同理valy=2×depzvalx就好了。

时间复杂度:O(nlogn)


1|3code

#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=3e6+10,inf=1e12; struct Heap{ ll cnt,w[N],t[N][2],dis[N]; ll Merge(ll x,ll y){ if(!x||!y)return x|y; if(w[x]>w[y])swap(x,y); t[x][1]=Merge(t[x][1],y); if(dis[t[x][0]]<dis[t[x][1]]) swap(t[x][0],t[x][1]); dis[x]=dis[t[x][1]]+1; return x; } ll Delete(ll x) {return Merge(t[x][0],t[x][1]);} void Ins(ll &x,ll val){ ++cnt;w[cnt]=val; x=Merge(x,cnt); } }T1,T2; struct node{ ll to,next,w; }a[N<<1]; ll n,tot,ans,ls[N],rt1[N],rt2[N],dep[N],c[N]; void addl(ll x,ll y,ll w){ a[++tot].to=y; a[tot].next=ls[x]; ls[x]=tot;a[tot].w=w; return; } void dfs(ll x,ll fa){ if(c[x]<0){ for(int i=0;i<-c[x];i++) T1.Ins(rt1[x],dep[x]-inf); } if(c[x]>0){ for(int i=0;i<c[x];i++) T2.Ins(rt2[x],dep[x]); } for(ll i=ls[x];i;i=a[i].next){ ll y=a[i].to; if(y==fa)continue; dep[y]=dep[x]+a[i].w; dfs(y,x); rt1[x]=T1.Merge(rt1[x],rt1[y]); rt2[x]=T2.Merge(rt2[x],rt2[y]); } while(rt1[x]&&rt2[x]){ ll X=rt1[x];rt1[x]=T1.Delete(rt1[x]);T1.t[X][0]=T1.t[X][1]=0; ll Y=rt2[x];rt2[x]=T2.Delete(rt2[x]);T2.t[Y][0]=T2.t[Y][1]=0; if(T1.w[X]+T2.w[Y]-2*dep[x]<0){ ll A=T1.w[X],B=T2.w[Y];ans+=A+B-2*dep[x]; T1.w[X]=2*dep[x]-B;rt1[x]=T1.Merge(rt1[x],X); T2.w[Y]=2*dep[x]-A;rt2[x]=T2.Merge(rt2[x],Y); } else{ rt1[x]=T1.Merge(rt1[x],X); rt2[x]=T2.Merge(rt2[x],Y); break; } } return; } signed main() { scanf("%lld",&n); for(ll i=1,x,y,w;i<n;i++){ scanf("%lld%lld%lld",&x,&y,&w); addl(x,y,w);addl(y,x,w); } for(ll i=1;i<=n;i++){ ll x,y; scanf("%lld%lld",&x,&y); c[i]=x-y; if(c[i]<0)ans+=-c[i]*inf; } dfs(1,0); printf("%lld\n",ans); return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/15918292.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(256)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
历史上的今天:
2021-02-21 YbtOJ#912-神秘语言【结论,欧拉定理】
2021-02-21 P4542-[ZJOI2011]营救皮卡丘【费用流,Floyd】
2021-02-21 YbtOJ#763-攻城略池【线段树合并】
点击右上角即可分享
微信分享提示