BZOJ 3638 k-Maximum Subsequence Sum

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/doyouseeman/article/details/50970738

Description

给一列数,要求支持操作:
1.修改某个数的值
2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少。

Solution

怎么做

可以用最大费用最大流做

把一个点i拆成两个点i1,i2,i1向i2连一个容量为1,费用为a[i]的边;然后i2向(i+1)1连一条容量为1,费用为0的边,然后其他的建边很明显。我们每次流完,为了防止再流一遍,把流过的边权取反,很明显要这样。

但是用网络流的做法比暴搜还慢啊

模拟一下网络流,我们发现,每次的最大费用最大流都是找一个最大和子段,然后再取反,我们可以用数据结构维护。

用什么

这种题目看上去就像一个数据结构维护的题。
支持查询,修改,维护和,最大与最小(因为我们取反的时候最大最小要交换)和每一段的左端点和右端点。
线段树明显可以搞定。

怎么维护左右端点

结构体套结构体!!!
一个struct套另一个struct,但是要重载运算符,这样的常数会小一点。

Code

常数真的好大!打的不优美……

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=100007;
int i,j,k,l,n,m,ans,o,tt;
int a[maxn];
struct haofana{
    int l,r,o;
    friend haofana operator +(haofana x,haofana y){
        haofana z;
        z.l=min(x.l,y.l);z.r=max(y.r,x.r);
        z.o=x.o+y.o;        
        return z;
    }
    friend bool operator <(haofana x,haofana y){
        return x.o<y.o;
    }
}ans1,b[200];
struct node{
    haofana lda,lxiao,rda,rxiao,sum,xiao,da;
    bool lazy;
}t[maxn*5];
void merge(node &x,node y,node z){
    x.sum=y.sum+z.sum;
    x.lda=max(y.lda,y.sum+z.lda);
    x.rda=max(z.rda,z.sum+y.rda);
    x.lxiao=min(y.lxiao,y.sum+z.lxiao);
    x.rxiao=min(z.rxiao,z.sum+y.rxiao);
    x.da=max(y.da,z.da);
    x.da=max(x.da,y.rda+z.lda);
    x.xiao=min(y.xiao,z.xiao);
    x.xiao=min(x.xiao,y.rxiao+z.lxiao);
    x.lazy=0;
}
void fan(int x){
    t[x].sum.o*=-1;
    t[x].da.o*=-1;
    t[x].lda.o*=-1;
    t[x].rda.o*=-1;
    t[x].lxiao.o*=-1;
    t[x].rxiao.o*=-1;
    t[x].lazy^=1;
    t[x].xiao.o*=-1;
    swap(t[x].da,t[x].xiao);
    swap(t[x].lda,t[x].lxiao);
    swap(t[x].rda,t[x].rxiao);

}
void lazydown(int x){
    if(t[x].lazy){
        fan(x*2);
        fan(x*2+1);
        t[x].lazy=0;
    }
}
void newdian(node &x,int l,int r,int p){
    x.lda.l=x.lxiao.l=x.rda.l=x.rxiao.l=x.sum.l=x.xiao.l=x.da.l=l;
    x.lda.r=x.lxiao.r=x.rda.r=x.rxiao.r=x.sum.r=x.xiao.r=x.da.r=r;
    x.lda.o=x.lxiao.o=x.rda.o=x.rxiao.o=x.sum.o=x.xiao.o=x.da.o=p;
    x.lazy=0;
}
void build(int x,int l,int r){
    if(l==r){
        newdian(t[x],l,r,a[l]);
    }
    else{
        int mid=(l+r)/2;
        build(x*2,l,mid);
        build(x*2+1,mid+1,r);
        merge(t[x],t[x*2],t[x*2+1]);
    }
}
void change(int x,int l,int r,int y,int z){
    if(l==r){
        newdian(t[x],l,r,z);
    }
    else{
        int mid=(l+r)/2;
        lazydown(x);
        if(y<=mid)change(x*2,l,mid,y,z);else change(x*2+1,mid+1,r,y,z);
        merge(t[x],t[x*2],t[x*2+1]);
    }
}
node find(int x,int l,int r,int y,int z){
    node q;
    if(l==y&&r==z){
        return t[x];
    }
    else{
        lazydown(x);
        int mid=(l+r)/2;
        if(z<=mid)return find(x*2,l,mid,y,z);else if (mid<y)return find(x*2+1,mid+1,r,y,z);
        else{
            merge(q,find(x*2,l,mid,y,mid),find(x*2+1,mid+1,r,mid+1,z));
            return q;
        }
    }
}
void negatea(int x,int l,int r,int y,int z){
    if(l==y&&r==z){
        fan(x);
    }
    else{
        lazydown(x);
        int mid=(l+r)/2;
        if(z<=mid)negatea(x*2,l,mid,y,z);else if(mid<y)negatea(x*2+1,mid+1,r,y,z);
        else{
            negatea(x*2,l,mid,y,mid);
            negatea(x*2+1,mid+1,r,mid+1,z);
        }
        merge(t[x],t[x*2],t[x*2+1]);
    }
}
int main(){
    freopen("0.in","r",stdin);
    scanf("%d",&n);
    fo(i,1,n){
        scanf("%d",&a[i]);
    }
    build(1,1,n);
    scanf("%d",&m);
    while(m--){
        scanf("%d",&k);
        ans=0;
        if(k){
            scanf("%d%d%d",&l,&tt,&o);
            int u=0;
            while(o--){
                ans1=find(1,1,n,l,tt).da;
                if(ans1.o<0)break;
                ans+=ans1.o;
                b[++u]=ans1;
                negatea(1,1,n,ans1.l,ans1.r);
            }
            printf("%d\n",ans);

            while(u){
                negatea(1,1,n,b[u].l,b[u].r);
                u--;
            }
        }else{
            scanf("%d%d",&l,&tt);
            change(1,1,n,l,tt);
        }
    }
}
展开阅读全文

没有更多推荐了,返回首页