k-Maximum Subsequence Sum

44 篇文章 0 订阅
15 篇文章 0 订阅

k-Maximum Subsequence Sum

题目描述:
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3638

题解

数据较小时,考虑费用流。为什么我没想到(雾)。
由于本题n较大,所以考虑进行人工增广。
用线段树维护区间最大子串,每次增广将其取反即可。
本题有4倍经验!!!

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<algorithm>
#define N 100010 
using namespace std;
int n,m,ans,tot,s[N];
struct info{int sum,ml,mr,num,pl,pr,l,r;}q[22];
struct node{int tag;info minn,maxn;}t[N*4];

class seg_tree
{
  void change(int x)
  {
    t[x].tag^=1;swap(t[x].maxn,t[x].minn);
  }
  void pushdown(int x)
  {
    if(!t[x].tag)return;
    int lc=x<<1,rc=lc+1;t[x].tag=0;
    change(lc);change(rc);
  }
  info merge(info a,info b)
  {
    info res;res.sum=a.sum+b.sum;
    res.ml=a.ml;res.mr=b.mr;
    res.pl=a.pl;res.pr=b.pr;
    if(a.sum+b.ml>res.ml)
      res.ml=a.sum+b.ml,res.pl=b.pl;
    if(b.sum+a.mr>res.mr)
      res.mr=b.sum+a.mr,res.pr=a.pr;
    res.num=a.mr+b.ml;res.l=a.pr;res.r=b.pl;
    if(a.num>res.num)
      res.num=a.num,res.l=a.l,res.r=a.r;
    if(b.num>res.num)
      res.num=b.num,res.l=b.l,res.r=b.r;
    return res;
  }
  void update(int x)
  {
    int lc=x<<1,rc=lc+1;
    t[x].maxn=merge(t[lc].maxn,t[rc].maxn); 
    t[x].minn=merge(t[lc].minn,t[rc].minn); 
  }
  public:
  void build(int x,int l,int r)
  {
    t[x].tag=0;
    if(l==r)
    {
      info res;
      res.sum=res.num=res.ml=res.mr=s[l];
      res.l=res.r=res.pl=res.pr=l;
      t[x].maxn=res;
      res.sum=res.num=res.ml=res.mr=-s[l];
      t[x].minn=res;
      return;
    }
    int mid=l+r>>1,lc=x<<1,rc=lc+1;
    build(lc,l,mid);build(rc,mid+1,r);
    update(x);
  }
  void modify(int x,int l,int r,int des,int val)
  {
    if(l==r)
    {
      info res;
      res.sum=res.num=res.ml=res.mr=val;
      res.l=res.r=res.pl=res.pr=l;
      t[x].maxn=res;
      res.sum=res.num=res.ml=res.mr=-val;
      t[x].minn=res;
      return;
    }
    int mid=l+r>>1,lc=x<<1,rc=lc+1;
    pushdown(x);
    if(des<=mid)modify(lc,l,mid,des,val);
    else modify(rc,mid+1,r,des,val);
    update(x);
  }
  void reverse(int x,int l,int r,int ql,int qr)
  {
    if(ql<=l&&r<=qr){change(x);return;}
    int mid=l+r>>1,lc=x<<1,rc=lc+1;
    pushdown(x);
    if(ql<=mid)reverse(lc,l,mid,ql,qr);
    if(qr>mid)reverse(rc,mid+1,r,ql,qr);
    update(x);
  }
  info qry(int x,int l,int r,int ql,int qr)
  {
    if(ql<=l&&r<=qr)return t[x].maxn;
    int mid=l+r>>1,lc=x<<1,rc=lc+1;
    pushdown(x);
    if(qr<=mid)return qry(lc,l,mid,ql,qr);
    if(ql>mid)return qry(rc,mid+1,r,ql,qr);
    return merge(qry(lc,l,mid,ql,qr),qry(rc,mid+1,r,ql,qr)); 
  }
}T;

int main()
{
  int tp,x,y,k;
  scanf("%d",&n);
  for(int i=1;i<=n;i++)scanf("%d",&s[i]);
  T.build(1,1,n);
  scanf("%d",&m);
  for(int i=1;i<=m;i++)
  {
    scanf("%d%d%d",&tp,&x,&y);
    if(tp==1)
    {
      scanf("%d",&k);ans=0;tot=0;
      while(k--)
      {
        info p=T.qry(1,1,n,x,y);
        if(p.num<0)break;
        T.reverse(1,1,n,p.l,p.r);
        ans+=p.num;q[++tot]=p; 
      }
      for(int i=1;i<=tot;i++)
        T.reverse(1,1,n,q[i].l,q[i].r);
      printf("%d\n",ans);
    }
    else T.modify(1,1,n,x,y);
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值