正确做法应该是线段树呢
然而ODT开O2后可以卡着时间过
主要的trick就是旋转操作不用真的旋转,记一个tag就可以计算编号为i的珠子的实际位置了
就这样,好像没别的了....
#include<bits/stdc++.h>
using namespace std;
const int N=500005;
int n,m,c;
inline int read(){
int s=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) s=s*10+ch-'0',ch=getchar();
return s;
}
struct node{
int l,r;mutable int v;
node(){}
node(int L,int R,int V){l=L,r=R,v=V;}
inline bool operator < (const node & a) const {
return l<a.l;
}
};
set<node> s;
int mov,rev;
#define IT set<node>::iterator
inline IT split(int x){
IT it=s.lower_bound(node(x,-1,0));
if(it!=s.end()&&it->l==x) return it;
--it;
int l=it->l,r=it->r,v=it->v;
s.erase(it);s.insert(node(l,x-1,v));
return s.insert(node(x,r,v)).first;
}
inline void assign(int l,int r,int v){
IT itr=split(r+1),itl=split(l);
s.erase(itl,itr);s.insert(node(l,r,v));
}
inline int get_col(int x){
IT it=s.lower_bound(node(x,-1,0));
if(it!=s.end()&&it->l==x) return it->v;
return (--it)->v;
}
inline int query(int l,int r){
int ans=0,la=-1;
IT itr=split(r+1),itl=split(l);
for(; itl!=itr; ++itl){
if(itl->v!=la) ans++;
la=itl->v;
}
return ans;
}
inline int real_pos(int x){
if(rev) x=n-x+2;x-=mov;
x=x%n;if(x<1) x+=n;
return x;
}
int main(){
n=read(),c=read();
int x,l,r;char op[10];
for(int i=1;i<=n;i++) x=read(),s.insert(node(i,i,x));
m=read();
while(m--){
scanf("%s",op);
if(op[0]=='R') {
x=read();mov+=rev?-x:x;
mov=mov%n;if(mov<0) x+=n;
}else if(op[0]=='F') rev^=1;
else if(op[0]=='S'){
l=read(),r=read();
l=real_pos(l),r=real_pos(r);
int a=get_col(l),b=get_col(r);
assign(l,l,b);assign(r,r,a);
}else if(op[0]=='P'){
l=read(),r=read(),x=read();
l=real_pos(l),r=real_pos(r);
if(rev) swap(l,r);
if(l<=r) assign(l,r,x);
else assign(1,r,x),assign(l,n,x);
}else if(op[1]=='S'){
int ans;
l=read(),r=read();
l=real_pos(l),r=real_pos(r);
if(rev) swap(l,r);
if(l<=r) ans=query(l,r);
else {
ans=query(1,r)+query(l,n);
if(ans>1) ans-=(get_col(1)==get_col(n));
}
printf("%d\n",ans);
}else {
int ans=query(1,n);
printf("%d\n",ans>1?ans-(get_col(1)==get_col(n)):ans);
}
}
return 0;
}