bzoj1493 [NOI2007]项链工厂(splay)
2018-01-18 22:01
281 查看
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 31 2 3 2 1
4
C
R 2
P 5 5 2
CS 4 1
Sample Output
41
HINT
注意旋转命令旋转“珠子”但不改变“位置”的编号,而反转命令始终以位置 1 为对称轴。例如当 N=10 时,项链上的位置编号如图1:但注意此时项链上的位置编号仍然如图1所示,于是翻转的对称轴不变。因而再执行一次“F”命令时,项链的颜色如图4所示。
关于CountSegment命令
CS命令表示查询一个“线段”中有多少个“部分”。尤其注意当查询的长度等于 N 时,我们仍然将查询部分作为“线段”理解。例如在图4所示的情况中,执行“CS 1 10”命令,查询从位置 1 开始到位置 10 结束的这个长度为 10 的线段中有多少个“部分”,于是得到返回值 3 。与之形成对照的是,若执行“C”命令,返回值则为 2
[Submit][Status][Discuss]
分析:
平衡树
在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 ; int ch [2],pre ,v ,ls ,rs ,size ,cover ,co ; bool rev ; 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; }
相关文章推荐
- BZOJ_1493_[NOI2007]项链工厂_Splay
- [BZOJ1493][NOI2007]项链工厂(splay)
- bzoj1493: [NOI2007]项链工厂 splay
- BZOJ1493: [NOI2007]项链工厂 Splay
- BZOJ 1493 NOI2007 项链工厂 Splay
- [BZOJ1493][NOI2007]项链工厂
- BZOJ1493 : [NOI2007]项链工厂
- bzoj1493: [NOI2007]项链工厂
- BZOJ1493 [NOI2007]项链工厂
- 【BZOJ】1493 [NOI2007]项链工厂 线段树
- BZOJ1493 NOI2007 项链工厂 线段树模拟
- [BZOJ1493][NOI2007]项链工厂
- bzoj 1493 [NOI2007]项链工厂 线段树
- 【BZOJ-1493】项链工厂 Splay
- bzoj 1493: [NOI2007]项链工厂 (平衡树)
- BZOJ 1493 NOI 2007 项链工厂 Splay
- bzoj 1493: [NOI2007]项链工厂(线段树)
- bzoj1493[NOI2007]项链工厂 线段树
- [BZOJ]1493 [NOI2007]项链工厂 线段树
- [bzoj1493]1493: [NOI2007]项链工厂 线段树