P5500 [LnOI2019] 真正的 OIer 从不女装
P5500 [LnOI2019] 真正的 OIer 从不女装
题意简述 :
维护一个序列,支持两种操作:
1.区间覆盖。
2.在区间
其中女装操作是指对于
Solution:
首先我们思考一下如果没有这个略显怪异的女装操作的话我们该怎么做这题:
很简单的线段树对吧,维护几个值
我们再来看一下女装操作到底在干什么:
假设
假设原区间长这样:
女装过后:
将区间整个翻转显然不会影响答案:
到这里我们不难发现:女装的实质就是将一段序列
然后我们再来思考一下女装会对答案产生什么样的影响:将这个序列断开又反拼之后,
前面已经说过真正有用的女装操作其实就一次而已,所以对于最终的答案,我们女装之后对答案可能的最大贡献即为:
但还要注意的是,因为
然后这题就愉快的做完了。
Code:
#include<bits/stdc++.h> const int N=2e5+5; using namespace std; int col[N]; //Segment_Tree struct Tree{ int lmx,rmx,mx,l,r,tag; int col[2]; }; struct Segment_Tree{ #define ls x<<1 #define rs x<<1|1 Tree t[N<<2]; void pushup(Tree &T,Tree L,Tree R) { int l=L.l,r=R.r,mid1=L.r,mid2=R.l; T.lmx= L.lmx + (l+L.lmx==mid2&&L.col[1]==R.col[0] ? R.lmx : 0); T.rmx= R.rmx + (r-R.rmx==mid1&&L.col[1]==R.col[0] ? L.rmx : 0); T.mx=max({T.lmx,T.rmx,L.mx,R.mx,(L.col[1]==R.col[0] ? L.rmx+R.lmx : 0)}); T.l=l,T.r=r; T.col[0]=L.col[0],T.col[1]=R.col[1]; return ; } void change(Tree &T,int k) { int len=T.r-T.l+1; T=Tree{len,len,len,T.l,T.r,k,k,k}; } void pushdown(int x) { if(!t[x].tag)return ; int tag=t[x].tag;t[x].tag=0; change(t[ls],tag);change(t[rs],tag); } void build(int x,int l,int r) { if(l==r) { t[x]=Tree{1,1,1,l,r,0,col[l],col[r]}; return ; } int mid=l+r>>1; build(ls,l,mid);build(rs,mid+1,r); pushup(t[x],t[ls],t[rs]); } void upd(int x,int L,int R,int k) { if(L<=t[x].l&&t[x].r<=R) { change(t[x],k); return; } pushdown(x); int mid=t[x].l+t[x].r>>1; if(L<=mid)upd(ls,L,R,k); if(mid<R) upd(rs,L,R,k); pushup(t[x],t[ls],t[rs]); } void query(int x,int L,int R,Tree &res) { if(L<=t[x].l&&t[x].r<=R) { if(!res.l)res=t[x]; else pushup(res,res,t[x]); return; } int mid=t[x].l+t[x].r>>1; pushdown(x); if(L<=mid)query(ls,L,R,res); if(mid<R) query(rs,L,R,res); } #undef ls #undef rs }T; char c[N]; int n,m; void work() { cin>>n>>m; for(int i=1;i<=n;i++) { scanf("%d",&col[i]); } T.build(1,1,n); for(int i=1,l,r,k;i<=m;i++) { scanf("%s",c); scanf("%d%d%d",&l,&r,&k); if(c[0]=='R') { T.upd(1,l,r,k); } if(c[0]=='Q') { int ans=0; Tree res={0,0,0,0,0,0,0,0}; T.query(1,l,r,res); if(k)ans=max(res.mx,min(r-l+1,(res.col[0]==res.col[1] ? res.lmx+res.rmx : 0))); else ans=res.mx; printf("%d\n",ans); } } } int main() { //freopen("P5500.in","r",stdin);freopen("P5500.out","w",stdout); work(); return 0; }
分类:
Luogu
, 高级数据结构 / 线段树