CF903G Yet Another Maxflow Problem

題面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
*/
相關文章
相關標籤/搜索