【CF903G】Yet Another Maxflow Problem 线段树
【CF903G】Yet Another Maxflow Problem
题意:一张图分为两部分,左边有n个点A,右边有m个点B,所有Ai->Ai+1有边,所有Bi->Bi+1有边,某些Ai->Bj有边,每条边都有一定的容量。
先要求你支持两种操作:
1.修改某条Ai->Ai+1的边的容量
2.询问从A1到Bm的最大流
n,m<=100000,流量<=10^9
题解:很有思维含量的题。
首先,我们把求最大流变成求最小割。容易发现,我们最多只会割一条Ai->Ai+1的边和一条Bi->Bi+1的边。
假设我们割掉了Ai->Ai+1的边,如果右边割掉的是Bj->Bj+1的边,那么我们还要割掉所有Ax->By的边(x<=i,y>j)。我们可以先预处理出对于每个i,最优的j是哪个。只需要从n到1枚举每个i,然后将从i连出去的边一条一条加进去,并用线段树维护区间加,全局最值即可。
由于每次只修改A的值,所以每个i选择的j是不变的,所以用堆维护一下最大值即可。
#include <cstdio> #include <cstring> #include <iostream> #include <queue> #include <vector> #define lson x<<1 #define rson x<<1|1 using namespace std; const int maxn=200010; typedef long long ll; ll s[maxn<<2],tag[maxn<<2],f[maxn],A[maxn],B[maxn]; vector<int> C[maxn],D[maxn]; vector<int>::iterator ci,di; int n,m,q; struct heap { priority_queue<ll,vector<ll>,greater<ll> > p1,p2; inline void erase(ll x) {p2.push(x);} inline void push(ll x) {p1.push(x);} inline ll top() { while(!p2.empty()&&p1.top()==p2.top()) p1.pop(),p2.pop(); return p1.top(); } }p; void build(int l,int r,int x) { if(l==r) { s[x]=B[l]; return ; } int mid=(l+r)>>1; build(l,mid,lson),build(mid+1,r,rson); s[x]=min(s[lson],s[rson]); } void updata(int l,int r,int x,int a,int b,int c) { if(a<=l&&r<=b) { s[x]+=c,tag[x]+=c; return ; } if(tag[x]) s[lson]+=tag[x],s[rson]+=tag[x],tag[lson]+=tag[x],tag[rson]+=tag[x],tag[x]=0; int mid=(l+r)>>1; if(a<=mid) updata(l,mid,lson,a,b,c); if(b>mid) updata(mid+1,r,rson,a,b,c); s[x]=min(s[lson],s[rson]); } inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();} while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar(); return ret*f; } int main() { n=rd(),m=rd(),q=rd(); int i,a; for(i=1;i<n;i++) A[i]=rd(),B[i+1]=rd(); for(i=1;i<=m;i++) a=rd(),C[a].push_back(rd()),D[a].push_back(rd()); build(1,n,1); for(i=1;i<=n;i++) { for(ci=C[i].begin(),di=D[i].begin();ci!=C[i].end();ci++,di++) updata(1,n,1,1,*ci,*di); f[i]=s[1],p.push(A[i]+f[i]); } printf("%I64d\n",p.top()); for(i=1;i<=q;i++) { a=rd(),p.erase(A[a]+f[a]),A[a]=rd(),p.push(A[a]+f[a]); printf("%I64d\n",p.top()); } return 0; }
| 欢迎来原网站坐坐! >原文链接<