[codeforces903G]Yet Another Maxflow Problem

来源:互联网 发布:5g网络的股票有哪些 编辑:程序博客网 时间:2024/06/05 11:36

题目大意

给定一个2n个节点的图,其中n个点在A集,n个点在B集。且称A集第i个点为ai(B集类似)。每个ai(i < n)向ai+1连一条给定容量的边(B也一样),还有m条边从ax连到ay,容量给定。
有q次操作,每次修改一条ax连向ax+1的边的容量(x和容量给定)。你需要对每次操作以及操作前输出以a1为源点,bn为汇点的最大流。

n,m,q≤200000

分析

首先最大流=最小割
考虑没有修改怎么做。
可以枚举割掉连接ai和ai+1的边(i=n表示不割),然后只需要考虑m条横跨边中起点编号小于等于i的边。这时枚举割掉连接bj-1与bj的边(j=1表示不割),答案只需要再加上横跨边中终点编号大于等于j的边。
我们发现顺序枚举i时,割B集边的最小值可以用线段树来维护
接下来设Ans(i)表示割掉ai与ai+1连边的答案。由于只修改A集的边,我们发现每次修改只有Ans(x)变化,这里也可以线段树维护

时间复杂度O(nlogn)

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int N=2e5+5,M=524444;typedef long long LL;int n,m,q,h[N],e[N],nxt[N],v[N],A[N],B[N];LL t[M],tag[M],Now[N];char c;int read(){    int x=0,sig=1;    for (c=getchar();c<'0' || c>'9';c=getchar()) if (c=='-') sig=-1;    for (;c>='0' && c<='9';c=getchar()) x=x*10+c-48;    return x*sig;}void Add(int l,int r,int a,int b,LL v,int x){    if (l==a && r==b)    {        tag[x]+=v; t[x]+=v; return;    }    int mid=l+r>>1;    if (tag[x]!=0)    {        tag[x<<1]+=tag[x]; t[x<<1]+=tag[x]; tag[x<<1|1]+=tag[x]; t[x<<1|1]+=tag[x];        tag[x]=0;    }    if (b<=mid) Add(l,mid,a,b,v,x<<1);else if (a>mid) Add(mid+1,r,a,b,v,x<<1|1);else    {        Add(l,mid,a,mid,v,x<<1); Add(mid+1,r,mid+1,b,v,x<<1|1);    }    t[x]=min(t[x<<1],t[x<<1|1]);}int main(){    n=read(); m=read(); q=read();    for (int i=1;i<n;i++)    {        A[i]=read(); B[i+1]=read(); Add(1,n,i+1,i+1,B[i+1],1);    }    for (int i=1,x;i<=m;i++)    {        x=read(); e[i]=read(); v[i]=read();        nxt[i]=h[x]; h[x]=i;    }    for (int i=1;i<=n;i++)    {        for (int j=h[i];j;j=nxt[j]) Add(1,n,1,e[j],v[j],1);        Now[i]=A[i]+t[1];    }    memset(t,0,sizeof(t));    memset(tag,0,sizeof(tag));    for (int i=1;i<=n;i++) Add(1,n,i,i,Now[i],1);    printf("%lld\n",t[1]);    for (int x,y;q--;)    {        x=read(); y=read();        Add(1,n,x,x,y-A[x],1); A[x]=y;        printf("%lld\n",t[1]);    }    return 0;}
原创粉丝点击