CF903G Yet Another Maxflow Problem
阿新 • • 發佈:2020-07-13
題目傳送門
分析:
考慮把最大流轉換成最小割來處理這個問題
考慮這個圖的特性:
如果說我們要割去\(A_i\)到\(A_{i+1}\)的邊,那麼對於\(j>i\),我們就沒必要割去\(A_j\)到\(A_{j+1}\)的邊了
\(B\)同理,這樣\(A\)和\(B\)中我們只需要至多各自割掉一條邊
因為有不割\(A\)或\(B\),而多割一些中間的邊代價更小的情況,由於處理起來比較麻煩,我們可以優化一下
\(A_0\)到\(A_1\),\(B_n\)到\(B_{n+1}\)連代價為0的邊,求\(A_0\)到\(B_{n+1}\)的最小割
這樣\(A\)和\(B\)中我們就可以各自割掉恰好一條邊找到最小代價
假設割\(A_u\)
\(a_u+b_v+sum_{i\leq u,j>v}c_{i,j}\)
由於修改的只有\(a_u\),對於每個\(v\),後面的一部分的最小代價不收影響
按順序列舉\(u\),加入必須割掉的邊,用線段樹維護取哪個\(v\)代價最小,即維護全域性最小值
修改直接單點修改就好了
複雜度\(O(nlogn)\)
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<queue> #include<set> #include<map> #include<vector> #define maxn 200005 #define pii pair<int,int> using namespace std; inline int getint() { int num=0,flag=1;char c; while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1; while(c>='0'&&c<='9')num=num*10+c-48,c=getchar(); return num*flag; } int n,m,q; long long A[maxn],B[maxn],C[maxn]; vector<pii >G[maxn]; long long mn[maxn<<2],lz[maxn<<2]; inline void build(int i,int l,int r) { lz[i]=0; if(l==r){mn[i]=B[l];return;} int mid=(l+r)>>1; build(i<<1,l,mid),build(i<<1|1,mid+1,r); mn[i]=min(mn[i<<1],mn[i<<1|1]); } inline void pushdown(int i) {if(lz[i]){mn[i<<1]+=lz[i],mn[i<<1|1]+=lz[i];lz[i<<1]+=lz[i],lz[i<<1|1]+=lz[i];lz[i]=0;}} inline void update(int i,int l,int r,int ql,int qr,int w) { if(ql>r||qr<l)return; if(ql<=l&&r<=qr){mn[i]+=w,lz[i]+=w;return;} int mid=(l+r)>>1; pushdown(i); update(i<<1,l,mid,ql,qr,w),update(i<<1|1,mid+1,r,ql,qr,w); mn[i]=min(mn[i<<1],mn[i<<1|1]); } int main() { n=getint(),m=getint(),q=getint(); for(int i=2;i<=n;i++)A[i-1]=getint(),B[i]=getint(); while(m--) { int u=getint(),v=getint(),w=getint(); G[u].push_back(make_pair(v,w)); } build(1,1,n); for(int i=1;i<=n;i++) { for(int j=0;j<G[i].size();j++)update(1,1,n,1,G[i][j].first,G[i][j].second); C[i]=mn[1]; } for(int i=1;i<=n;i++)B[i]=A[i]+C[i]; build(1,1,n); printf("%lld\n",mn[1]); while(q--) { int p=getint(),x=getint(); update(1,1,n,p,p,x-A[p]),A[p]=x; printf("%lld\n",mn[1]); } }