题意
给定一个2n个节点的图,其中n个点在A集,n个点在B集。且称A集第i个点为ai(B集类似)。每个ai(i < n)向ai+1连一条给定容量的边(B也一样),还有m条边从ax连到by,容量给定。 有q次操作,每次修改一条ax连向ax+1的边的容量(x和容量给定)。你需要对每次操作以及操作前输出以a1为源点,bn为汇点的最大流。
n,m,q≤200000
分析
首先第一个最大流=最小割
然后就考虑怎么割,这个问题好像很像是线段树问题
假设割掉一条ai->ai+1的边,就要维护一条bj->bj+1的边割掉最优,什么时候是最优的呢
就是
Ans(i)=min(∑x≤i,y≥jcost(x,y)+bj+ai)
A
n
s
(
i
)
=
m
i
n
(
∑
x
≤
i
,
y
≥
j
c
o
s
t
(
x
,
y
)
+
b
j
+
a
i
)
这个感性理解一下很容易,就是如果割了bj这条边,还有之前a1…ai有边连到bj+1…bn的话,也要割掉
当然也有不割ai的情况,就是把所有边都割掉,所以先扫一遍ai,对b开线段树,然后如果有向bi连边,就对割bi以前的边打一个加标记,表示你以前的边就算割了还要割这条边
然后再对a开线段树,对于Ans(i)表示一定割这条ai的边,改的时候就是单点修改,询问直接问根就好了
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll N = 200010;
inline ll read()
{
char ch=getchar(); ll p=0; ll f=1;
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
struct node{ll x,y,d,next;}edge[N]; ll len,first[N];
void ins(ll x,ll y,ll d){len++; edge[len].x=x; edge[len].y=y; edge[len].d=d; edge[len].next=first[x]; first[x]=len;}
ll ans[N],rt,tot,lc[N<<2],rc[N<<2],lazy[N<<2],c[N<<2];
ll a[N],b[N];
void push_down(ll u)
{
if(lazy[u])
{
lazy[lc[u]] += lazy[u]; lazy[rc[u]]+=lazy[u];
c[lc[u]]+=lazy[u]; c[rc[u]] += lazy[u];
lazy[u] = 0;
}
}
void link(ll &u,ll L,ll R,ll k,ll cc)
{
if(!u) u=++tot,c[u] = 0;
if(L==R){c[u] += cc; return ;}
push_down(u);
ll mid=(L+R)>>1;
if(k<=mid) link(lc[u],L,mid,k,cc);
else link(rc[u],mid+1,R,k,cc);
c[u] = min(c[lc[u]] , c[rc[u]]);
}
void chg(ll u,ll L,ll R,ll l,ll r,ll cc)
{
if(l>r) return ;
if(L==l && R==r){c[u]+=cc; lazy[u]+=cc; return ;}
ll mid=(L+R)>>1;
push_down(u);
if(r<=mid) chg(lc[u],L,mid,l,r,cc);
else if(l>mid) chg(rc[u],mid+1,R,l,r,cc);
else
{
chg(lc[u],L,mid,l,mid,cc);
chg(rc[u],mid+1,R,mid+1,r,cc);
}
c[u] = min(c[lc[u]] , c[rc[u]]);
}
int main()
{
ll n = read(); ll m = read(); ll q = read(); len = 0; memset(first,-1,sizeof(first));
for(ll i=1;i<n;i++) a[i] = read(),b[i]=read();
for(ll i=1;i<=m;i++)
{
ll x = read(); ll y = read(); ll d = read();
ins(x,y,d);
}
rt=tot=0; memset(lc,0,sizeof(lc)); memset(rc,0,sizeof(rc)); memset(c,63,sizeof(c));
for(ll i=1;i<n;i++) link(rt,1,n-1,i,b[i]); ll s=0;
for(ll i=1;i<=n;i++)
{
ll x = i;
for(ll k=first[x];k!=-1;k=edge[k].next)
{
ll y = edge[k].y;
chg(rt,1,n-1,1,y-1,edge[k].d); s+=edge[k].d;
}
ans[i] = min(s,c[rt]) + a[i];
}
rt=tot=0; memset(lc,0,sizeof(lc)); memset(rc,0,sizeof(rc)); memset(c,63,sizeof(c));
for(ll i=1;i<=n;i++) link(rt,1,n,i,ans[i]);
printf("%lld\n",c[rt]);
while(q--)
{
ll x = read(); ll w = read();
link(rt,1,n,x,w-a[x]); a[x] = w;
printf("%lld\n",c[rt]);
}
return 0;
}