[ 线段树 ] Codeforces903G

转换成求最小割。
注意到 AB 中最多各删去一条边。
所以答案由三部分组成: A 中的一条边、 B 中的一条边、 AB 间的边。
先用线段树维护最小值求出 fi 表示删去 A ai ai+1 的边后的最小值。然后再用棵线段树维护 fi 就好了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=200010;
ll c[N<<2],p[N<<2],f[N];
int k,n,m,Q;
int a[N];
int t[N],nx[N],w[N],h[N],num;
int x,y,z;
inline void Add(int x,int y,int z){
    t[++num]=y;w[num]=z;nx[num]=h[x];h[x]=num;
}
void Build(int x,int l,int r){
    p[x]=0;
    if(l==r){
        c[x]=f[l];
        return;
    }
    int Mid=l+r>>1;
    Build(x<<1,l,Mid);Build(x<<1|1,Mid+1,r);
    c[x]=min(c[x<<1],c[x<<1|1]);
}
inline void Down(int x){
    c[x<<1]+=p[x];p[x<<1]+=p[x];
    c[x<<1|1]+=p[x];p[x<<1|1]+=p[x];
    p[x]=0;
}
void Update(int x,int l,int r,int L,int R,int y){
    if(l>R||r<L)return;
    if(l>=L&&r<=R){
        c[x]+=y;p[x]+=y;
        return;
    }
    if(p[x])Down(x);
    int Mid=l+r>>1;
    Update(x<<1,l,Mid,L,R,y);Update(x<<1|1,Mid+1,r,L,R,y);
    c[x]=min(c[x<<1],c[x<<1|1]);
}
inline void Init(){
    Build(1,0,n-1);
    for(int i=1;i<=n;i++){
        for(int j=h[i];j;j=nx[j])Update(1,0,n-1,0,t[j]-1,w[j]);
        f[i]=c[1]+a[i];
    }
    Build(1,1,n);
}
int main(){
    scanf("%d%d%d",&n,&m,&Q);
    for(int i=1;i<n;i++)scanf("%d%d",&a[i],&f[i]);
    while(m--)scanf("%d%d%d",&x,&y,&z),Add(x,y,z);
    Init();
    printf("%I64d\n",c[1]);
    while(Q--){
        scanf("%d%d",&x,&y);
        Update(1,1,n,x,x,y-a[x]);a[x]=y;
        printf("%I64d\n",c[1]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值