Description
T公司是一家专门生产彩色珠子项链的公司,其生产的项链设计新颖、款式多样、价格适中,广受青年人的喜爱。
最近T公司打算推出一款项链自助生产系统,使用该系统顾客可以自行设计心目中的美丽项链。该项链自助生产系
统包括硬件系统与软件系统,软件系统与用户进行交互并控制硬件系统,硬件系统接受软件系统的命令生产指定的
项链。该系统的硬件系统已经完成,而软件系统尚未开发,T公司的人找到了正在参加全国信息学竞赛的你,你能
帮助T公司编写一个软件模拟系统吗?一条项链包含 N 个珠子,每个珠子的颜色是 1,2,…,c 中的一种。项链
被固定在一个平板上,平板的某个位置被标记位置 1 ,按顺时针方向其他位置被记为 2,3,…,N。
你将要编写的软件系统应支持如下命令:
Input
输入文件第一行包含两个整数 N,c ,分别表示项链包含的珠子数目以及颜色数目。
第二行包含 N 个整数,x1,x2,…,xn ,表示从位置 1 到位置 N 的珠子的颜色,1≤xi≤c 。
第三行包含一个整数 Q ,表示命令数目。接下来的 Q 行每行一条命令,如上文所述。N≤500000 ,Q≤500000,c≤1000
Output
对于每一个 C 和 CS 命令,应输出一个整数代表相应的答案。
Sample Input
5 3
1 2 3 2 1
4
C
R 2
P 5 5 2
CS 4 1
1 2 3 2 1
4
C
R 2
P 5 5 2
CS 4 1
Sample Output
4
1
1
HINT
注意旋转命令旋转“珠子”但不改变“位置”的编号,而反转命令始终以位置 1 为对称轴。例如当 N=10 时,项链上的位置编号如图1:
但注意此时项链上的位置编号仍然如图1所示,于是翻转的对称轴不变。因而再执行一次“F”命令时,项链的颜色如图4所示。
关于CountSegment命令
CS命令表示查询一个“线段”中有多少个“部分”。尤其注意当查询的长度等于 N 时,我们仍然将查询部分作为“线段”理解。例如在图4所示的情况中,执行“CS 1 10”命令,查询从位置 1 开始到位置 10 结束的这个长度为 10 的线段中有多少个“部分”,于是得到返回值 3 。与之形成对照的是,若执行“C”命令,返回值则为 2
CS命令表示查询一个“线段”中有多少个“部分”。尤其注意当查询的长度等于 N 时,我们仍然将查询部分作为“线段”理解。例如在图4所示的情况中,执行“CS 1 10”命令,查询从位置 1 开始到位置 10 结束的这个长度为 10 的线段中有多少个“部分”,于是得到返回值 3 。与之形成对照的是,若执行“C”命令,返回值则为 2
分析:
平衡树
在splay中,我们维护:
cover:区间覆盖标记(区间全部涂成一个颜色)
v:结点颜色
ls:区间最左边结点的颜色
rs:区间最右边结点的颜色
size:区间大小
co:区间内的颜色数目
rev:翻转标记
F 对[2,n]打翻转标记即可
R 将最后k个元素插入到1的前面
S 交换两个点的颜色,把两个点splay到根,更新节点的信息
P 注意染色的时候可能需要分成两段
C 注意判断1,n两个节点的颜色是否相同,相同且颜色数!=1的话颜色段数要-1
CS 可能需要分两段统计答案,和在一起的时候判断1,n的颜色是否相同,相同的话答案-1
tip
写了两节课,交上去T了
加了inline和读优也没有用
后来发现是Rotate的问题(找了一节课啊)
改了改交上去,终于变成WA了。。。
mdzz,调不出来了,只能参考一下学姐的code了
查询区间的时候,为了便于处理,我们一般在两端各加一个新结点
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=500010;
int n,m,C,top=0,root,a[N];
int ch[N][2],pre[N],v[N],ls[N],rs[N],size[N],cover[N],co[N];
bool rev[N];
void clear(int bh)
{
ch[bh][0]=ch[bh][1]=size[bh]=co[bh]=pre[bh]=0;
}
inline int get(int bh)
{
return (ch[pre[bh]][0]==bh? 0:1);
}
inline void update(int bh)
{
int l=ch[bh][0]; int r=ch[bh][1];
ls[0]=rs[0]=-2;
co[bh]=1;
ls[bh]=(l?ls[l]:v[bh]); rs[bh]=(r?rs[r]:v[bh]);
size[bh]=size[l]+size[r]+1;
if (l) co[bh]+=co[l];
if (r) co[bh]+=co[r];
if (rs[l]==v[bh]||ls[r]==v[bh]) co[bh]--;
if (rs[l]==v[bh]&&ls[r]==v[bh]) co[bh]--;
}
void change(int bh)
{
swap(ch[bh][0],ch[bh][1]);
swap(ls[bh],rs[bh]);
rev[bh]^=1;
}
void color(int bh,int c)
{
v[bh]=ls[bh]=rs[bh]=c;
cover[bh]=c; co[bh]=1;
}
inline void push(int bh)
{
if (rev[bh])
{
change(ch[bh][0]);
change(ch[bh][1]);
rev[bh]=0;
}
if (cover[bh])
{
color(ch[bh][0],cover[bh]);
color(ch[bh][1],cover[bh]);
cover[bh]=0;
}
}
inline void rotate(int bh)
{
int fa=pre[bh];
int grand=pre[fa];
int wh=get(bh);
ch[fa][wh]=ch[bh][wh^1];
pre[ch[fa][wh]]=fa;
ch[bh][wh^1]=fa;
pre[fa]=bh;
pre[bh]=grand;
if (grand) ch[grand][ch[grand][0]==fa? 0:1]=bh;
update(fa);
update(bh);
}
inline void down(int bh) {if (pre[bh]) down(pre[bh]); push(bh);}
inline void splay(int bh,int mb)
{
down(bh);
for (int fa;(fa=pre[bh])!=mb;rotate(bh))
if (pre[fa]!=mb)
rotate(get(fa)==get(bh)? fa:bh);
if (!mb) root=bh;
}
inline int build(int l,int r,int fa)
{
if (l>r) return 0;
int now=++top;
if (l==r)
{
v[now]=ls[now]=rs[now]=a[l];
co[now]=1; size[now]=1; pre[now]=fa;
return now;
}
int mid=(l+r)>>1;
v[now]=a[mid];
ch[now][0]=build(l,mid-1,now);
ch[now][1]=build(mid+1,r,now);
pre[now]=fa;
update(now);
return now;
}
inline int find_pm(int x) //查找排名为x的结点标号
{
int now=root;
while (1)
{
push(now);
if (ch[now][0]&&size[ch[now][0]]>=x) now=ch[now][0];
else
{
int tmp=(ch[now][0]? size[ch[now][0]]:0);
tmp++;
if (tmp>=x) return now;
now=ch[now][1];
x-=tmp;
}
}
}
inline void reverse(int x)
{
int f1=find_pm(n-x+1);
int f2=find_pm(n+2);
splay(f1,0); splay(f2,f1);
int now=ch[ch[root][1]][0]; pre[now]=0;
ch[ch[root][1]][0]=0;
update(ch[root][1]); update(root);
f1=find_pm(1);
f2=find_pm(2);
splay(f1,0); splay(f2,f1);
ch[ch[root][1]][0]=now; pre[now]=ch[root][1];
update(ch[root][1]); update(root);
}
inline void fan()
{
int f1=find_pm(2);
int f2=find_pm(n+2);
splay(f1,0); splay(f2,f1);
int now=ch[ch[root][1]][0];
change(now);
update(ch[root][1]);
update(root);
}
inline void print(int x,int y,int z)
{
if (x<=y) //询问的是一个连续区间
{
int f1=find_pm(x);
int f2=find_pm(y+2);
splay(f1,0); splay(f2,f1);
color(ch[ch[root][1]][0],z);
update(ch[root][1]); update(root);
}
else //询问的区间被n号结点分成了两部分
{
int f1=find_pm(1);
int f2=find_pm(y+2);
splay(f1,0); splay(f2,f1);
color(ch[ch[root][1]][0],z);
update(ch[root][1]); update(root);
f1=find_pm(x);
f2=find_pm(n+2);
splay(f1,0); splay(f2,f1);
color(ch[ch[root][1]][0],z);
update(ch[root][1]); update(root);
}
}
inline void ask(int x,int y)
{
if (x<=y) //询问的是一个连续区间
{
int f1=find_pm(x);
int f2=find_pm(y+2);
splay(f1,0); splay(f2,f1);
printf("%d\n",co[ch[ch[root][1]][0]]);
}
else //询问的区间被n号结点分成了两部分
{
int f1=find_pm(1);
int f2=find_pm(y+2);
splay(f1,0); splay(f2,f1);
int ans=co[ch[ch[root][1]][0]];
f1=find_pm(x);
f2=find_pm(n+2);
splay(f1,0); splay(f2,f1);
ans+=co[ch[ch[root][1]][0]];
f1=find_pm(2); f2=find_pm(n+1);
if (v[f1]==v[f2]) ans--;
printf("%d\n",ans);
}
}
int main()
{
scanf("%d%d",&n,&C);
a[1]=a[n+2]=-1;
for (int i=2;i<=n+1;i++) scanf("%d",&a[i]);
root=build(1,n+2,0);
scanf("%d",&m);
char s[5]; int x,y,z;
for (int i=1;i<=m;i++)
{
scanf("%s",s);
if (s[0]=='R')
{
scanf("%d",&x);
reverse(x);
}
else if (s[0]=='F') fan();
else if (s[0]=='S')
{
scanf("%d%d",&x,&y);
int f1=find_pm(x+1);
int f2=find_pm(y+1);
swap(v[f1],v[f2]);
splay(f1,0); splay(f2,0);
}
else if (s[0]=='P')
{
scanf("%d%d%d",&x,&y,&z);
print(x,y,z);
}
else if (s[1]=='S')
{
scanf("%d%d",&x,&y);
ask(x,y);
}
else
{
int f1=find_pm(2);
int f2=find_pm(n+1);
int ans=co[root]-2;
if (ans>1&&v[f1]==v[f2]) ans--;
printf("%d\n",ans);
}
}
return 0;
}