CF903G Yet Another Maxflow Problem

Link
先转化为最小割。
显然(A ightarrow A,B ightarrow B)的边最多割一条。
那么如果我们割的是(A_u ightarrow A_{u+1},B_{v-1} ightarrow B_v),那么总共的代价是(sumlimits_{i=1}^usumlimits_{j=v}^ne(i,j)+e(A_u,A_{u+1})+e(B_{v-1},B_v))
最开始的情况我们可以用线段树对每一个(u)计算出最优的(v)
之后修改只会修改(e(A_u,A_{u+1}))这一部分,所以对每个(u),最优的(v)是不会变的,用树状数组/线段树搞搞就完事了。

#include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
#include<utility>
#define pi pair<int,int>
#define fi first
#define se second
using std::vector;
using std::pair;
using ll=long long;
const int N=200007;
int read(){int x=0,c=getchar();while(!isdigit(c))c=getchar();while(isdigit(c))x=x*10+c-48,c=getchar();return x;}
ll min(ll a,ll b){return a<b? a:b;}
vector<pi>e[N];ll a[N],b[N],c[N],mn[N<<2],tag[N<<2];
#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)>>1)
void pushup(int p){mn[p]=min(mn[ls],mn[rs]);}
void modify(int p,ll v){mn[p]+=v,tag[p]+=v;}
void pushdown(int p){if(!tag[p])return;modify(ls,tag[p]),modify(rs,tag[p]),tag[p]=0;}
void build(int p,int l,int r)
{
    if(l==r) return (void)(mn[p]=b[l]);
    build(ls,l,mid),build(rs,mid+1,r),pushup(p);
}
void update(int p,int l,int r,int L,int R,int x)
{
    if(R<l||r<L) return ;
    if(L<=l&&r<=R) return modify(p,x);
    pushdown(p),update(ls,l,mid,L,R,x),update(rs,mid+1,r,L,R,x),pushup(p);
}
#undef ls
#undef rs
#undef mid
int main()
{
    int n=read(),m=read(),q=read();
    for(int i=1;i<n;++i) a[i]=read(),b[i+1]=read();
    for(int i=1,u,v,w;i<=m;++i) u=read(),v=read(),w=read(),e[u].emplace_back(v,w);
    build(1,1,n);
    for(int u=1;u<=n;c[u++]=mn[1]) for(auto[v,w]:e[u]) update(1,1,n,1,v,w);
    memset(tag+1,0,n<<5),memset(mn+1,0,n<<5);
    for(int i=1;i<=n;++i) b[i]=a[i]+c[i];
    build(1,1,n),printf("%I64d
",mn[1]);
    for(int u,w;q;--q) u=read(),w=read(),update(1,1,n,u,u,w-a[u]),a[u]=w,printf("%I64d
",mn[1]);
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12194476.html