【题解】
仔细探索题目性质:
1. "段数"具有类似结合律的性质,可以用线段树维护,断环为链,但线段树不易进行旋转、翻转操作
2. 考虑用函数记录从初始到当前操作的变换方式,将对数列的变换转化为对询问的处理
发现:若函数 f(x)=k*x+b表示询问的位置x对应的初始位置,则旋转a之后,函数为:f(x)=k*(x-a)+b; 翻转之后为:f(x)=k*(n+2-x)+b
3. 在纸上模拟了部分操作,发现无论旋转、翻转,1~n总连续出现
由上述性质可知,由函数计算的询问区间的各点,对应的初始位置仍连续,所以可以用函数进行转换,且k总为正负1,可以用来记录当前环顺时针增大还是减小
因此:
实时维护函数,不变环而改变询问
并用线段树的每个节点记录四个信息:setv:整个区间是否被整体赋值、lv/rv区间左/右端点的颜色、cntv区间内的段数
用setv,lv,rv维护cntv即可
【代码】
#include<stdio.h> #include<stdlib.h> int a[500005],setv[2000000],lv[2000000],rv[2000000],cntv[2000000]; int n,c,k=1,b=0; void jh(int* a,int* b) { int t=*a; *a=*b; *b=t; } int f(int x)//询问中的想、在线段树(原始数据)中的位置 { return ((k*x+b)%n+n-1)%n+1; } void pushdown(int o) { setv[o*2]=setv[o*2+1]=setv[o]; setv[o]=-1; } void wh(int o)//根据当前的setv值维护其他信息 { if(setv[o]!=-1)//包含叶结点 { lv[o]=rv[o]=setv[o]; cntv[o]=1; return; } lv[o]=lv[o*2]; rv[o]=rv[o*2+1]; cntv[o]=cntv[o*2]+cntv[o*2+1]; if(rv[o*2]==lv[o*2+1]) cntv[o]--; } void build(int o,int left,int right) { int mid=(left+right)/2; if(left==right) setv[o]=a[left]; else { setv[o]=-1; build(o*2,left,mid); build(o*2+1,mid+1,right); } wh(o); } void xg(int p,int x,int y,int o,int left,int right) { int mid=(left+right)/2; if(x<=left&&right<=y) setv[o]=p; else//不包含叶结点 { if(setv[o]!=-1) pushdown(o); if(x<=mid) xg(p,x,y,o*2,left,mid); else wh(o*2); if(y>mid) xg(p,x,y,o*2+1,mid+1,right); else wh(o*2+1); } wh(o); } int cx(int x,int y,int o,int left,int right) { int mid=(left+right)/2,ans=0; if(setv[o]!=-1) return 1;//注意 if(x<=left&&right<=y) return cntv[o]; if(x<=mid) ans+=cx(x,y,o*2,left,mid); if(y>mid) ans+=cx(x,y,o*2+1,mid+1,right); if(x<=mid&&y>mid&&rv[o*2]==lv[o*2+1]) ans--; return ans; } int get(int x,int o,int left,int right)//得到线段树第x个叶结点的颜色 { int mid=(left+right)/2; if(setv[o]!=-1) return setv[o]; if(x<=mid) return get(x,o*2,left,mid); return get(x,o*2+1,mid+1,right); } int main() { char s[20]; int i,Q,x,y,z,tx,ty,ans; scanf("%d%d",&n,&c); for(i=1;i<=n;i++) scanf("%d",&a[i]); build(1,1,n); scanf("%d",&Q); for(;Q>0;Q--) { scanf("%s",s); if(s[0]=='R') { scanf("%d",&x); b=(b-k*x)%n; } if(s[0]=='F') { b=(b+(n+2)*k)%n; k=-k; } if(s[0]=='S') { scanf("%d%d",&x,&y); x=f(x); y=f(y); tx=get(x,1,1,n); ty=get(y,1,1,n); xg(ty,x,x,1,1,n); xg(tx,y,y,1,1,n); } if(s[0]=='P') { scanf("%d%d%d",&x,&y,&z); x=f(x); y=f(y); if(k==-1) jh(&x,&y); if(x<=y) xg(z,x,y,1,1,n); else { xg(z,x,n,1,1,n); xg(z,1,y,1,1,n); } } if(s[0]=='C'&&s[1]!='S') { ans=cx(1,n,1,1,n); if(ans>1&&get(1,1,1,n)==get(n,1,1,n)) ans--; printf("%d\n",ans); } if(s[0]=='C'&&s[1]=='S') { scanf("%d%d",&x,&y); x=f(x); y=f(y); if(k==-1) jh(&x,&y); if(x<=y) ans=cx(x,y,1,1,n); else { ans=cx(x,n,1,1,n)+cx(1,y,1,1,n); if(get(1,1,1,n)==get(n,1,1,n)) ans--; } printf("%d\n",ans); } } return 0; }