CF903G-Yet Another Maxflow Problem【線段樹,最大流】
阿新 • • 發佈:2021-09-27
正題
題目連結:https://www.luogu.com.cn/problem/CF903G
題目大意
有\(n\)個\(A\)點,\(n\)個\(B\)點,第\(A_i\rightarrow A_{i+1}\)和\(B_{i}\rightarrow B_{i+1}\)都連有不同流量的邊,然後有\(m\)對\(A_i\rightarrow B_j\)連邊。
\(q\)次修改一條\(A_i\rightarrow A_{i+1}\)的邊,求最大流。
\(1\leq n,m,q\leq 2\times 10^5\)
解題思路
首先最大流=最小割,所以我們可以求最小割。
然後這題就差不多了,左邊和右邊最多割一條,然後剩下的邊都要割掉。
先用線段樹處理每條\(A\)邊右邊的代價,然後左邊修改的話就用優先佇列維護一下就好了。
時間複雜度:\(O(n\log n)\)(\(n,m,q\)同級)
code
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define ll long long #define mp(x,y) make_pair(x,y) using namespace std; const ll N=2e5+10; ll n,m,t,a[N],ans[N],w[N<<2],lazy[N<<2]; priority_queue<pair<ll,ll> > q; vector<pair<ll,ll> >E[N]; void Downdata(ll x){ if(!lazy[x])return; w[x*2]+=lazy[x];w[x*2+1]+=lazy[x]; lazy[x*2]+=lazy[x];lazy[x*2+1]+=lazy[x]; lazy[x]=0;return; } void Change(ll x,ll L,ll R,ll l,ll r,ll val){ if(L==l&&R==r){w[x]+=val;lazy[x]+=val;return;} ll mid=(L+R)>>1;Downdata(x); if(r<=mid)Change(x*2,L,mid,l,r,val); else if(l>mid)Change(x*2+1,mid+1,R,l,r,val); else Change(x*2,L,mid,l,mid,val),Change(x*2+1,mid+1,R,mid+1,r,val); w[x]=min(w[x*2],w[x*2+1]);return; } void Solve(){ do{ pair<ll,ll> x=q.top(); if(-x.first!=ans[x.second]+a[x.second]) {q.pop();continue;} printf("%lld\n",-x.first); break; }while(1); return; } signed main() { scanf("%lld%lld%lld",&n,&m,&t); for(ll i=1,x;i<n;i++){ scanf("%lld%lld",&a[i],&x); Change(1,1,n,i+1,i+1,x); } for(ll i=1;i<=m;i++){ ll x,y,w; scanf("%lld%lld%lld",&x,&y,&w); E[x].push_back(mp(y,w)); } for(ll i=1;i<=n;i++){ for(ll j=0;j<E[i].size();j++) Change(1,1,n,1,E[i][j].first,E[i][j].second); ans[i]=w[1]; q.push(mp(-a[i]-ans[i],i)); } Solve(); while(t--){ ll x,w; scanf("%lld%lld",&x,&w); a[x]=w;q.push(mp(-a[x]-ans[x],x)); Solve(); } return 0; }