[Luogu 5500][线段树]真正的oler从不女装

题意:定义一个序列的权值为里面的最长的子线段满足线段内的数一样
给出一个序列,每次给出其子区间l,r作为序列,你可以至多执行k次操作,使得操作后序列的权值最大,输出最大权值。其中,一次操作选定 p p p, r e v ( l , p ) , r e v ( p + 1 , r ) rev(l,p),rev(p+1,r) rev(l,p),rev(p+1,r)
解法:这是一道本蒟蒻永远无法做出来的神题。
翻转三次及其以上是无任何意义的
于是一棵线段树维护一下相关信息即可

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m;
#define Maxn 200010
int a[Maxn];
int tag[Maxn<<2];
struct Data{
	int ans;
	int lval,lans;
	int rval,rans;
	int len;
}tree[Maxn<<2];
Data merge(Data a,Data b){
	Data res;
	res.len=a.len+b.len;
	res.lval=a.lval;
	if(a.lans==a.len&&b.lval==a.lval)res.lans=a.lans+b.lans;
	else res.lans=a.lans;
	res.rval=b.rval;
	if(b.rans==b.len&&a.rval==b.rval)res.rans=a.rans+b.rans;
	else res.rans=b.rans;
	res.ans=max(a.ans,b.ans);
	if(a.rval==b.lval)res.ans=max(res.ans,a.rans+b.lans);
	return res;
}
void push_up(int k){tree[k]=merge(tree[k<<1],tree[k<<1|1]);}
inline void Maketag(int k,int val){
	tag[k]=val;
	tree[k].ans=tree[k].lans=tree[k].rans=tree[k].len;
	tree[k].lval=tree[k].rval=val;
}
void push_down(int k){
	if(tag[k]){
		Maketag(k<<1,tag[k]);
		Maketag(k<<1|1,tag[k]);
		tag[k]=0;
	}
}
void Build_Tree(int k,int l,int r){
	if(l==r){
		tree[k].ans=tree[k].lans=tree[k].rans=tree[k].len=1;
		tree[k].lval=tree[k].rval=a[l];
		return;
	}
	int mid=(l+r)>>1;
	Build_Tree(k<<1,l,mid);
	Build_Tree(k<<1|1,mid+1,r);
	push_up(k);
}
void Modify(int k,int l,int r,int L,int R,int val){
	if(l==L&&r==R){
		Maketag(k,val);
		return;
	}
	push_down(k);
	int mid=(l+r)>>1;
	if(R<=mid)Modify(k<<1,l,mid,L,R,val);
	else if(mid<L)Modify(k<<1|1,mid+1,r,L,R,val);
	else{
		Modify(k<<1,l,mid,L,mid,val);
		Modify(k<<1|1,mid+1,r,mid+1,R,val);
	}
	push_up(k);
}
Data Query(int k,int l,int r,int L,int R){
	if(l==L&&r==R)return tree[k];
	push_down(k);
	int mid=(l+r)>>1;
	if(R<=mid)return Query(k<<1,l,mid,L,R);
	else if(mid<L)return Query(k<<1|1,mid+1,r,L,R);
	else return merge(Query(k<<1,l,mid,L,mid),Query(k<<1|1,mid+1,r,mid+1,R));
}

inline void rd(int &x){
	x=0;char ch=getchar();
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9'){
		x=x*10+ch-'0';
		ch=getchar();
	}
}
char opt[5];

int main(){
    rd(n);rd(m);
	for(register int i=1;i<=n;++i)rd(a[i]);
	Build_Tree(1,1,n);
	int l,r,x,k;
	for(register int tt=1;tt<=m;++tt){
		scanf("%s",opt);
		if(opt[0]=='R'){
			rd(l);rd(r);rd(x);
			Modify(1,1,n,l,r,x);
		}else{
			rd(l);rd(r);rd(k);
			Data res=Query(1,1,n,l,r);
			if(!k)printf("%d\n",res.ans);
			else{
				int Ans=res.ans;
				if(Ans==r-l+1)printf("%d\n",Ans);
				else{
					if(res.lval==res.rval)Ans=max(Ans,res.lans+res.rans);
					printf("%d\n",Ans);
				}
			} 
		}
	}	
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值