【原创】线段树好题 CF280D k-Maximum Subsequence Sum

题面

Crloss你也有今天

分析

最大区间和都会做吧?

最大K区间和就是找最大1区间和,然后把这段区间乘上-1,然后重复。
如果一个数被选了偶数次就相当于不选。
然后如果当前的最大1区间和<=0了,就停下来。

代码

#include
#include
#include
#include
#include
using namespace std;

void Read(int &p)
{
	p=0;
	int f=1;
	char c=getchar();
	while(c<'0' || c>'9') 
	{
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0' && c<='9')
		p=p*10+c-'0',c=getchar();
	p*=f;
}

const int MAXN=102030,MAXT=402030,inf=402030;
int n,q,u,v,k,opt,ans,cnt,arr[MAXN],cgl[MAXN],cgr[MAXN];
struct sgmtree{int xl,xr,nl,nr,lzy,lxr,lnr,rxl,rnl,sum,mx,mn,lmx,rmx,lmn,rmn;}las,now,bad,tre[MAXT];

#define lson pos<<1
#define rson pos<<1|1
#define mid ((lef+rig)>>1)

inline void rvr(int pos)
{
	tre[pos].sum=-tre[pos].sum;
	tre[pos].lmn=-tre[pos].lmn,tre[pos].lmx=-tre[pos].lmx,swap(tre[pos].lmn,tre[pos].lmx),swap(tre[pos].lnr,tre[pos].lxr);
	tre[pos].rmn=-tre[pos].rmn,tre[pos].rmx=-tre[pos].rmx,swap(tre[pos].rmn,tre[pos].rmx),swap(tre[pos].rnl,tre[pos].rxl); 
	tre[pos].mx=-tre[pos].mx,tre[pos].mn=-tre[pos].mn,swap(tre[pos].mn,tre[pos].mx),swap(tre[pos].nl,tre[pos].xl),swap(tre[pos].nr,tre[pos].xr);
}

inline void pushdown(int pos)
{
	if(tre[pos].lzy&1) tre[pos].lzy=0,tre[lson].lzy++,tre[rson].lzy++,rvr(lson),rvr(rson);
}

inline void joint(sgmtree &up,sgmtree lef,sgmtree rig)
{
	up.sum=lef.sum+rig.sum;
	up.mx=lef.mx,up.xl=lef.xl,up.xr=lef.xr;
	if(rig.mx>up.mx) up.mx=rig.mx,up.xl=rig.xl,up.xr=rig.xr;
	if(lef.rmx+rig.lmx>up.mx) up.mx=lef.rmx+rig.lmx,up.xl=lef.rxl,up.xr=rig.lxr;
	up.mn=lef.mn,up.nl=lef.nl,up.nr=lef.nr;
	if(rig.mn<up.mn) up.mn=rig.mn,up.nl=rig.nl,up.nr=rig.nr;
	if(lef.rmn+rig.lmn<up.mn) up.mn=lef.rmn+rig.lmn,up.nl=lef.rnl,up.nr=rig.lnr;
	up.lmn=lef.lmn,up.lnr=lef.lnr; if(lef.sum+rig.lmn<up.lmn) up.lmn=lef.sum+rig.lmn,up.lnr=rig.lnr;
	up.lmx=lef.lmx,up.lxr=lef.lxr; if(lef.sum+rig.lmx>up.lmx) up.lmx=lef.sum+rig.lmx,up.lxr=rig.lxr;
	up.rmn=rig.rmn,up.rnl=rig.rnl; if(rig.sum+lef.rmn<up.rmn) up.rmn=lef.rmn+rig.sum,up.rnl=lef.rnl;
	up.rmx=rig.rmx,up.rxl=rig.rxl; if(rig.sum+lef.rmx>up.rmx) up.rmx=lef.rmx+rig.sum,up.rxl=lef.rxl;
}

inline void pushup(int pos){joint(tre[pos],tre[lson],tre[rson]);}

void build(int pos,int lef,int rig)
{
	if(lef==rig)
	{
		tre[pos].lzy=0; 
		tre[pos].sum=tre[pos].lmx=tre[pos].lmn=tre[pos].rmx=tre[pos].rmn=tre[pos].mn=tre[pos].mx=arr[lef];
		tre[pos].lxr=tre[pos].lnr=tre[pos].rxl=tre[pos].rnl=tre[pos].nl=tre[pos].nr=tre[pos].xl=tre[pos].xr=rig;
		return;
	}
	build(lson,lef,mid),build(rson,mid+1,rig),pushup(pos);
}

void change(int pos,int lef,int rig,int l,int r)
{
    if(lef>r || rig<l) return;
    if(l<=lef && rig<=r) {tre[pos].lzy++,rvr(pos); return;}
    pushdown(pos),change(lson,lef,mid,l,r),change(rson,mid+1,rig,l,r),pushup(pos);
}

sgmtree query(int pos,int lef,int rig,int l,int r)
{
	if(r<lef || rig<l) return bad;
	if(l<=lef && rig<=r) return tre[pos];
	pushdown(pos);
	sgmtree ls=query(lson,lef,mid,l,r),rs=query(rson,mid+1,rig,l,r);
	if(ls.mn!=inf && rs.mn!=inf) {joint(now,ls,rs); return now;}
	if(ls.mn!=inf) return ls;
	return rs;
}

void update(int pos,int lef,int rig,int tar,int del)
{
	if(lef>tar || rig<tar) return;
	if(lef==tar && rig==tar)
	{
		tre[pos].mn=tre[pos].mx=tre[pos].sum=tre[pos].lmx=tre[pos].lmn=tre[pos].rmx=tre[pos].rmn=del;
		return;
	}
	pushdown(pos),update(lson,lef,mid,tar,del),update(rson,mid+1,rig,tar,del),pushup(pos);
}

int main()
{
	bad.sum=0,bad.lmx=bad.rmx=bad.mx=-inf,bad.lmn=bad.rmn=bad.mn=inf;
	Read(n);
	for(int i=1;i<=n;i++) Read(arr[i]);
	Read(q),build(1,1,n);
	while(q--)
	{
		Read(opt);
		if(opt==0) Read(u),Read(v),update(1,1,n,u,v);
		else
		{
			ans=0,cnt=0,Read(u),Read(v),Read(k);
			while(k--)
			{
				las=query(1,1,n,u,v);
				if(las.mx>0) ans+=las.mx,cnt++,cgl[cnt]=las.xl,cgr[cnt]=las.xr,change(1,1,n,cgl[cnt],cgr[cnt]); 
				else break;	
			}
			cout<<ans<<endl;
			for(int i=1;i<=cnt;i++) change(1,1,n,cgl[i],cgr[i]);//!
			//printf("%d %d %d\n",tre[1].mx,tre[1].xl,tre[1].xr);
		}
	}	
}

//sum:子段和 lzy:是否乘-1的懒标记
//lmx:最大左子段和 rmx:最大右子段和 mx:最大子段和 
//lmn:最小左子段和 rmm:最小右子段和 mn:最小子段和
//xl:最大子段和的左端点 xr:最大子段和的右端点
//nl:最小子段和的左端点 nr:最小子段和的右端点
//rxl:最大右子段和的左端点 lnr:最小右子段和的左端点
//lxr:最大左子段和的右端点 lnr:最小左子段和的右端点
//我太难了

打感叹号那一句话,之前我写成while(cnt--) change(1,1,n,cgl[cnt],cgr[cnt])了,所以打死过不了样例。

哈哈哈哈哈哈哈哈哈,你太蠢了,哈哈哈哈哈哈呜呜呜呜呜、

你可能感兴趣的:(#,题目,#,☠☠☠☠☠哼本人已死亡,#,☆☆★★★哦有点难度呢)