CF280D k-Maximum Subsequence Sum

一、题目

点此看题

二、解法

想了好久这结论终于自己整出来了,开心。

你看这题 \(dp\) 稳超时,而且又没有什么好的贪心方法,不妨先建出网络流模型。

显然可以费用流,建 \(n+1\) 个点,相邻两个点之间连有向边,费用为 \(a_i\) 流量为 \(1\),每个点都连源汇点,然后搞个限 \(k\) 点流量的点,跑最大费用最大流即可。

但是不能直接跑网络流,因为流过一条边之后相当于反向并且费用添上负号,我们可以根据这个图总结出贪心策略:选取最大的子段,然后把这个子段负号,再继续此过程 \(k\) 次即可

用线段树维护即可,要维护最大子段和最小子段以及对应的区间,时间复杂度 \(O(mk\log n)\)

#include <cstdio>
#include <iostream>
#include <queue>
using namespace std;
const int M = 100005;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m;
struct rec
{
    int l,r,c;
    rec(int L=0,int R=0,int C=0) : l(L) , r(R) , c(C) {}
    bool operator < (const rec &b) const
    {
        return c<b.c;
    }
    rec operator + (const rec &b) const
    {
        return rec(l,b.r,c+b.c);
    }
};queue<rec> q;
struct node
{
    rec smax,smin,lmax,lmin,rmax,rmin,sum;int fl;
    node() {fl=0;}
}s[4*M];
node operator + (node x,node y)
{
    node r;
    r.smax=max(x.smax,y.smax);
    r.smax=max(r.smax,x.rmax+y.lmax);
    r.smin=min(x.smin,y.smin);
    r.smin=min(r.smin,x.rmin+y.lmin);
    r.lmax=max(x.lmax,x.sum+y.lmax);
    r.rmax=max(y.rmax,x.rmax+y.sum);
    r.lmin=min(x.lmin,x.sum+y.lmin);
    r.rmin=min(y.rmin,x.rmin+y.sum);
    r.sum=x.sum+y.sum;
    return r;
}
void rev(int i)
{
    swap(s[i].smax,s[i].smin);
    swap(s[i].lmax,s[i].lmin);
    swap(s[i].rmax,s[i].rmin);
    s[i].smax.c*=-1;s[i].smin.c*=-1;
    s[i].lmax.c*=-1;s[i].lmin.c*=-1;
    s[i].rmax.c*=-1;s[i].rmin.c*=-1;
    s[i].sum.c*=-1;s[i].fl^=1;
}
void down(int i)
{
    if(!s[i].fl) return ;
    rev(i<<1);rev(i<<1|1);
    s[i].fl=0; 
}
void add(int i,int l,int r,int id,int v)
{
    if(l==r)
    {
        s[i].smax=s[i].smin=s[i].lmax=s[i].sum=
        s[i].lmin=s[i].rmax=s[i].rmin=rec(l,l,v);
        return ;
    }
    int mid=(l+r)>>1;down(i);
    if(mid>=id) add(i<<1,l,mid,id,v);
    else add(i<<1|1,mid+1,r,id,v);
    s[i]=s[i<<1]+s[i<<1|1];
}
void upd(int i,int l,int r,int L,int R)
{
    if(L>r || l>R) return ;
    if(L<=l && r<=R)
    {
        rev(i);
        return ;
    }
    int mid=(l+r)>>1;down(i);
    upd(i<<1,l,mid,L,R);
    upd(i<<1|1,mid+1,r,L,R);
    s[i]=s[i<<1]+s[i<<1|1];
}
node ask(int i,int l,int r,int L,int R)
{
    if(L<=l && r<=R) return s[i];
    int mid=(l+r)>>1;down(i);
    if(R<=mid) return ask(i<<1,l,mid,L,R);
    if(L>mid) return ask(i<<1|1,mid+1,r,L,R);
    return ask(i<<1,l,mid,L,R)+ask(i<<1|1,mid+1,r,L,R);
}
signed main()
{
    n=read();
    for(int i=1;i<=n;i++)
        add(1,1,n,i,read());
    m=read();
    while(m--)
    {
        int op=read(),l=read(),r=read();
        if(op==0)
        {
        	add(1,1,n,l,r);
        	continue;
		}
		int k=read(),ans=0;
        while(k--)
        {
            rec t=ask(1,1,n,l,r).smax;
            if(t.c<=0) break;
            ans+=t.c;
            upd(1,1,n,t.l,t.r);
            q.push(t);
        }
        printf("%d\n",ans);
        while(!q.empty())
        {
            rec t=q.front();q.pop();
            upd(1,1,n,t.l,t.r);
        }
    }
}
posted @ 2021-06-10 20:29  C202044zxy  阅读(62)  评论(0编辑  收藏  举报