【题解】
仔细探索题目性质:
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;
}