題面c++
英文題面git
題意:一張圖分爲兩部分,左右都有 \(n\)個節點,\(a_i \rightarrow a_{i+1}\)連邊,\(b_i \rightarrow b_{i+1}\) 連邊,容量給出。ui
有 \(m\) 對\(a_i \rightarrow b_j\)有邊,容量給出。spa
你須要先求出原圖從\(a_1\) 到 \(b_n\) 的最大流,而後有 \(q\) 次操做,每次操做給出 \(i\),先修改\(a_i \rightarrow a_{i+1}\) 的邊的容量,而後詢問從 \(a_1\) 到 \(b_n\) 的最大流。\(n \leq 2\times 10^5\)。code
題解:考慮到最大流等於最小割,咱們考慮割邊的最優策略。排序
因爲全部邊都是單向邊,因此\(a\)和\(b\)內部的邊最多各割掉一條。那麼咱們就獲得了一個作法:枚舉刪掉的各是哪條邊,而後考慮一下有哪些\(a\)到\(b\)的邊要割掉,而後取個min。可是這樣是\(O(n^2)\)的,還不能支持修改。因此考慮只枚舉\(a\),而後算出哪條\(b\)是最優的。設\(f_{i,j}\)表示分別割掉了\(a_i \rightarrow a_{i+1}\)和\(b_j \rightarrow b_{j+1}\)的邊的最小割。那麼有:get
\(f_{i,j}=x_i+y_j+\sum_{a \leq i,b>j}w_{a,b}\)。發現後面的東西是個定值,因此把它算出來就好了。咱們把全部\(a\)到\(b\)之間的邊排序,那麼一條邊的貢獻至關於區間修改。用線段樹來維護就好了。it
咱們求出對於每一個\(i\)最小的\(j\)以後,修改就很簡單了。再開一棵線段樹維護便可。class
時間複雜度:\(O(nlogn)\)。im
代碼:
#include<bits/stdc++.h> using namespace std; #define re register int #define F(x,y,z) for(re x=y;x<=z;x++) #define FOR(x,y,z) for(re x=y;x>=z;x--) typedef long long ll; #define I inline void #define IN inline int #define C(x,y) memset(x,y,sizeof(x)) #define STS system("pause") template<class D>I read(D &res){ res=0;register D g=1;register char ch=getchar(); while(!isdigit(ch)){ if(ch=='-')g=-1; ch=getchar(); } while(isdigit(ch)){ res=(res<<3)+(res<<1)+(ch^48); ch=getchar(); } res*=g; } const ll INF=1e18+9; struct E{ int u,v;ll w; E(int _u=0,int _v=0,ll _w=0){u=_u;v=_v;w=_w;} friend bool operator < (E a,E b){return a.u<b.u;} }e[202000]; int n,m,q,a[202000],b[202000]; ll tr[808000],laz[808000],S,c[202000]; #define all 1,0,n-1 #define lt k<<1,l,mid #define rt k<<1|1,mid+1,r I build(int k,int l,int r){ if(l==r)return tr[k]=(ll)b[l],void(); re mid=(l+r)>>1;build(lt);build(rt); tr[k]=min(tr[k<<1],tr[k<<1|1]); } I add(int k,ll w){tr[k]+=w;laz[k]+=w;} I push_down(int k){add(k<<1,laz[k]);add(k<<1|1,laz[k]);laz[k]=0;} I modi(int k,int l,int r,int x,int y,ll w){ if(x>r||y<l)return; if(x<=l&&r<=y)return add(k,w),void(); if(laz[k])push_down(k); re mid=(l+r)>>1; modi(lt,x,y,w);modi(rt,x,y,w); tr[k]=min(tr[k<<1],tr[k<<1|1]); } I buildin(int k,int l,int r){ if(l==r)return tr[k]=c[l],void(); re mid=(l+r)>>1;buildin(lt);buildin(rt); tr[k]=min(tr[k<<1],tr[k<<1|1]); } I revi(int k,int l,int r,int x,ll w){ if(l==r)return tr[k]+=w,void(); re mid=(l+r)>>1; if(x<=mid)revi(lt,x,w); else revi(rt,x,w); tr[k]=min(tr[k<<1],tr[k<<1|1]); } int main(){ read(n);read(m);read(q); F(i,1,n-1)read(a[i]),read(b[i]); re X,Y,W; F(i,1,m)read(X),read(Y),read(W),e[i]=E(X,Y-1,W),S+=W; sort(e+1,e+1+m); re now=1;build(all);c[0]=INF; F(i,1,n){ while(now<=m&&e[now].u==i)modi(all,0,e[now].v,e[now].w),now++; c[i]=(ll)a[i]+tr[1]; // cout<<c[i]<<" "; } // cout<<endl; S=min(S,c[n]);buildin(all);printf("%lld\n",min(S,tr[1])); while(q--){ read(X);read(W); revi(all,X,W-a[X]);a[X]=W; printf("%lld\n",min(S,tr[1])); } return 0; } /* 4 3 2 1 2 3 4 5 6 2 2 7 1 4 8 4 3 9 1 100 2 100 */