题解 CF280D 【k-Maximum Subsequence Sum】
liangzihao · · 题解
因为
所以,每次增广相当于找到询问区间的最大子区间和,然后再把该区间取反(反向弧的费用是正向弧的相反数)。举个例子,如果第一次选了区间
因为不可能同时选共起点或共终点的区间,假如我们第一次取了
现在就可以用线段树维护了,相当于维护一个最大子区间值,当然,同时肯定要维护最大左区间和与最大右区间和区间和,单点修改就不用
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
const int maxn=1e5+7;
using namespace std;
int n,m,x,op,y,k;
struct rec{
int l,r,s;
};
rec operator + (rec x,rec y)
{
return (rec){x.l,y.r,x.s+y.s};
}
bool operator < (rec x,rec y)
{
return x.s<y.s;
}
struct node{
rec smax,smin,lmax,rmax,lmin,rmin,sum;
int rev;
}t[maxn*4];
queue <node> q;
void neww(int p,int l,int k)
{
t[p].smax=(rec){l,l,k};
t[p].lmax=(rec){l,l,k};
t[p].rmax=(rec){l,l,k};
t[p].smin=(rec){l,l,k};
t[p].lmin=(rec){l,l,k};
t[p].rmin=(rec){l,l,k};
t[p].sum=(rec){l,l,k};
}
node merge(node x,node y)
{
node z;
z.smax=max(x.smax,y.smax);
z.smax=max(z.smax,x.rmax+y.lmax);
z.smin=min(x.smin,y.smin);
z.smin=min(z.smin,x.rmin+y.lmin);
z.lmax=max(x.lmax,x.sum+y.lmax);
z.rmax=max(y.rmax,x.rmax+y.sum);
z.lmin=min(x.lmin,x.sum+y.lmin);
z.rmin=min(y.rmin,x.rmin+y.sum);
z.sum=x.sum+y.sum;
z.rev=0;
return z;
}
void clean(int p)
{
swap(t[p].smax,t[p].smin);
swap(t[p].lmax,t[p].lmin);
swap(t[p].rmax,t[p].rmin);
t[p].smax.s*=-1;
t[p].smin.s*=-1;
t[p].lmax.s*=-1;
t[p].lmin.s*=-1;
t[p].rmax.s*=-1;
t[p].rmin.s*=-1;
t[p].sum.s*=-1;
t[p].rev^=1;
}
void change(int p,int l,int r,int x,int k)
{
if (l==r)
{
neww(p,l,k);
return;
}
int mid=(l+r)/2;
if (t[p].rev)
{
clean(p*2);
clean(p*2+1);
t[p].rev^=1;
}
if (x<=mid) change(p*2,l,mid,x,k);
else change(p*2+1,mid+1,r,x,k);
t[p]=merge(t[p*2],t[p*2+1]);
}
void rev(int p,int l,int r,int x,int y)
{
if ((l==x) && (r==y))
{
clean(p);
return;
}
int mid=(l+r)/2;
if (t[p].rev)
{
clean(p*2);
clean(p*2+1);
t[p].rev^=1;
}
if (y<=mid) rev(p*2,l,mid,x,y);
else if (x>mid) rev(p*2+1,mid+1,r,x,y);
else
{
rev(p*2,l,mid,x,mid);
rev(p*2+1,mid+1,r,mid+1,y);
}
t[p]=merge(t[p*2],t[p*2+1]);
}
node query(int p,int l,int r,int x,int y)
{
if ((l==x) && (r==y)) return t[p];
int mid=(l+r)/2;
if (t[p].rev)
{
clean(p*2);
clean(p*2+1);
t[p].rev^=1;
}
if (y<=mid) return query(p*2,l,mid,x,y);
else if (x>mid) return query(p*2+1,mid+1,r,x,y);
else
{
return merge(query(p*2,l,mid,x,mid),query(p*2+1,mid+1,r,mid+1,y));
}
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d",&x);
change(1,1,n,i,x);
}
scanf("%d",&m);
for (int i=1;i<=m;i++)
{
scanf("%d",&op);
if (op==0)
{
scanf("%d%d",&x,&k);
change(1,1,n,x,k);
}
else
{
scanf("%d%d%d",&x,&y,&k);
int ans=0;
while (k--)
{
node d=query(1,1,n,x,y);
if (d.smax.s<0) break;
ans+=d.smax.s;
rev(1,1,n,d.smax.l,d.smax.r);
q.push(d);
}
printf("%d\n",ans);
while (!q.empty())
{
node d=q.front();
q.pop();
rev(1,1,n,d.smax.l,d.smax.r);
}
}
}
}