题目传送门
分析:
考虑把最大流转换成最小割来处理这个问题
考虑这个图的特性:
如果说我们要割去(A_i)到(A_{i+1})的边,那么对于(j>i),我们就没必要割去(A_j)到(A_{j+1})的边了
(B)同理,这样(A)和(B)中我们只需要至多各自割掉一条边
因为有不割(A)或(B),而多割一些中间的边代价更小的情况,由于处理起来比较麻烦,我们可以优化一下
(A_0)到(A_1),(B_n)到(B_{n+1})连代价为0的边,求(A_0)到(B_{n+1})的最小割
这样(A)和(B)中我们就可以各自割掉恰好一条边找到最小代价
假设割(A_u)到(A_{u+1}),(B_v)到(B_{v+1}),那么答案为
(a_u+b_v+sum_{ileq u,j>v}c_{i,j})
由于修改的只有(a_u),对于每个(v),后面的一部分的最小代价不收影响
按顺序枚举(u),加入必须割掉的边,用线段树维护取哪个(v)代价最小,即维护全局最小值
修改直接单点修改就好了
复杂度(O(nlogn))
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<vector>
#define maxn 200005
#define pii pair<int,int>
using namespace std;
inline int getint()
{
int num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
int n,m,q;
long long A[maxn],B[maxn],C[maxn];
vector<pii >G[maxn];
long long mn[maxn<<2],lz[maxn<<2];
inline void build(int i,int l,int r)
{
lz[i]=0;
if(l==r){mn[i]=B[l];return;}
int mid=(l+r)>>1;
build(i<<1,l,mid),build(i<<1|1,mid+1,r);
mn[i]=min(mn[i<<1],mn[i<<1|1]);
}
inline void pushdown(int i)
{if(lz[i]){mn[i<<1]+=lz[i],mn[i<<1|1]+=lz[i];lz[i<<1]+=lz[i],lz[i<<1|1]+=lz[i];lz[i]=0;}}
inline void update(int i,int l,int r,int ql,int qr,int w)
{
if(ql>r||qr<l)return;
if(ql<=l&&r<=qr){mn[i]+=w,lz[i]+=w;return;}
int mid=(l+r)>>1;
pushdown(i);
update(i<<1,l,mid,ql,qr,w),update(i<<1|1,mid+1,r,ql,qr,w);
mn[i]=min(mn[i<<1],mn[i<<1|1]);
}
int main()
{
n=getint(),m=getint(),q=getint();
for(int i=2;i<=n;i++)A[i-1]=getint(),B[i]=getint();
while(m--)
{
int u=getint(),v=getint(),w=getint();
G[u].push_back(make_pair(v,w));
}
build(1,1,n);
for(int i=1;i<=n;i++)
{
for(int j=0;j<G[i].size();j++)update(1,1,n,1,G[i][j].first,G[i][j].second);
C[i]=mn[1];
}
for(int i=1;i<=n;i++)B[i]=A[i]+C[i];
build(1,1,n);
printf("%lld
",mn[1]);
while(q--)
{
int p=getint(),x=getint();
update(1,1,n,p,p,x-A[p]),A[p]=x;
printf("%lld
",mn[1]);
}
}