[codeforces903G]Yet Another Maxflow Problem

题目大意

给定一个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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值