• CF280D k-Maximum Subsequence Sum【线段树】


    题目链接

    碎碎念

    刚开始:这怎么是个黑题啊,就是一个线段树而已啦。

    然后,这道题我断断续续调了两天。

    所以说,(flag)不要立得太早。

    题目解析

    如果题目没有说选(k)段不相交,而是只有一段的话,那就直接求最大子段和。

    但是这道题可以选(k)段的话,就相当于我们可以在最大子段和里断开(k-1)处((k-1)段),把一些会拖累答案的段退回去不要。

    考虑反悔贪心。

    我们取一个最大子段和出来,然后把选中的区间取反。

    重复这样的操作(k)次就可以得到答案。

    为什么呢?

    如果这一次选中的区间与之前选过的(取反了的)区间没有交集,相当于我们再选了新的一段。

    如果与之前选过的有交集,而我们之前又取了反,那就相当于把原来选的那一段给退了回去。如果两段区间(指新选的区间和原来选过的区间)不是包含关系,显然段数会多(1)。如果是包含关系,就相当于把原来的区间退回去,而新选的区间裂开了,所以区间总数还是多(1)

    如果把一个区间取反,最大子段和变最小子段和(的相反数) 。

    所以同时维护一个最小子段和

    或者写两个线段树 :一个维护正常的,一个维护相反数。

    如果修改,就交换这两个线段树的对应结点(感觉这种好写多了,本来刚开始维护了最小子段和,但最后还是屈服喏(qwq),并且优化了一下写法,把原来丑陋无比的(200+)的代码压得好看一点了。


    ►Code View

    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    using namespace std;
    #define N 100005
    #define MOD 998244353
    #define INF 0x3f3f3f3f
    int rd()
    {
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48); c=getchar();}
    	return f*x;
    }
    int n,k;
    pair<int,int> fx[N];
    int cnt;//记录下来被修改(取反)过的区间 每次查询时要返回来
    int a[N];
    struct node{
    	int sum,mxs,lmx,rmx;
    	int l,r,rr,ll;
    }tree[2][N<<2];
    bool tag[N<<2];//tag拿出来 合并的时候就不用记下来再搞回去 
    node Merge(node x,node y)
    {
    	node t;
    	t.sum=x.sum+y.sum;
    	t.mxs=t.lmx=t.rmx=-INF;
    	
    	if(x.lmx>t.lmx) t.lmx=x.lmx,t.rr=x.rr;
    	if(x.sum+y.lmx>t.lmx) t.lmx=x.sum+y.lmx,t.rr=y.rr;
    	
    	if(y.rmx>t.rmx) t.rmx=y.rmx,t.ll=y.ll;
    	if(y.sum+x.rmx>t.rmx) t.rmx=y.sum+x.rmx,t.ll=x.ll;
    	
    	if(x.mxs>t.mxs) t.mxs=x.mxs,t.l=x.l,t.r=x.r;
    	if(y.mxs>t.mxs) t.mxs=y.mxs,t.l=y.l,t.r=y.r;
    	if(x.rmx+y.lmx>t.mxs) t.mxs=x.rmx+y.lmx,t.l=x.ll,t.r=y.rr;//Cao 这里打成x.rr 
    	
    	return t;
    }
    void PushUp(int i)
    {
    	tree[0][i]=Merge(tree[0][i<<1],tree[0][i<<1|1]);
    	tree[1][i]=Merge(tree[1][i<<1],tree[1][i<<1|1]);
    }
    void Init(int i,int l,int val)
    {
    	tree[0][i].sum=tree[0][i].mxs=tree[0][i].lmx=tree[0][i].rmx=val;
    	tree[1][i].sum=tree[1][i].mxs=tree[1][i].lmx=tree[1][i].rmx=-val;
    	tree[0][i].l=tree[0][i].r=tree[0][i].rr=tree[0][i].ll=l;
    	tree[1][i].l=tree[1][i].r=tree[1][i].rr=tree[1][i].ll=l;
    }
    void Build(int i,int l,int r)
    {
    	if(l==r)
    	{
    		Init(i,l,a[l]);
    		return ;
    	}
    	int mid=(l+r)>>1;
    	Build(i<<1,l,mid);
    	Build(i<<1|1,mid+1,r);
    	PushUp(i);
    }
    void Shift(int i)
    {
    	swap(tree[0][i],tree[1][i]);
    	tag[i]^=1;
    }
    void PushDown(int i)
    {
    	if(tag[i]==1)
    	{
    		Shift(i<<1);
    		Shift(i<<1|1);
    		tag[i]=0;
    	}
    }
    void Update(int i,int l,int r,int ql,int qr)
    {
    	if(ql<=l&&r<=qr)
    	{
    		Shift(i);
    		return ;
    	}
    	PushDown(i);
    	int mid=(l+r)>>1;
    	if(ql<=mid) Update(i<<1,l,mid,ql,qr);
    	if(qr>mid) Update(i<<1|1,mid+1,r,ql,qr);
    	PushUp(i);
    }
    node Query(int i,int l,int r,int ql,int qr)
    {
    	if(ql<=l&&r<=qr) return tree[0][i];
    	PushDown(i);
    	int mid=(l+r)>>1;
    	if(qr<=mid) return Query(i<<1,l,mid,ql,qr);
    	else if(ql>mid) return Query(i<<1|1,mid+1,r,ql,qr);
    	return Merge(Query(i<<1,l,mid,ql,qr),Query(i<<1|1,mid+1,r,ql,qr));
    }
    void Modify(int i,int l,int r,int pos,int val)
    {
    	if(l==r)
    	{
    		Init(i,l,val);
    		return ;
    	}
    	PushDown(i);
    	int mid=(l+r)>>1;
    	if(pos<=mid) Modify(i<<1,l,mid,pos,val);
    	else Modify(i<<1|1,mid+1,r,pos,val);
    	PushUp(i);
    }
    int main()
    {
    	n=rd();
    	for(int i=1;i<=n;i++)
    		a[i]=rd();
    	Build(1,1,n);
    	int Q=rd();
    	while(Q--)
    	{
    		int opt=rd();
    		if(opt==0)
    		{
    			int i=rd(),val=rd();
    			Modify(1,1,n,i,val);
    		}
    		else
    		{
    			int l=rd(),r=rd(),k=rd();
    			int res=0;
    			while(k--)
    			{
    				node ans=Query(1,1,n,l,r);
    				if(ans.mxs<=0) break;
    				res+=ans.mxs;
    				fx[++cnt]=make_pair(ans.l,ans.r);
    				Update(1,1,n,ans.l,ans.r);
    			}
    			printf("%d
    ",res);
    			for(int i=cnt;i>=1;i--)
    				Update(1,1,n,fx[i].first,fx[i].second);
    			cnt=0;
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    4.24成果(冲刺1.7)
    4.23成果(冲刺1.6)
    4.22成果(冲刺1.5)
    4.21成果(冲刺1.4)
    4.20成果(冲刺1.3)
    4.19成果(冲刺1.2)
    4.18成果(冲刺1.1)
    计划会议
    需求评审
    电梯演讲
  • 原文地址:https://www.cnblogs.com/lyttt/p/14063796.html
Copyright © 2020-2023  润新知