bzoj 1493: [NOI2007]项链工厂 (平衡树)

1493: [NOI2007]项链工厂

Time Limit: 30 Sec   Memory Limit: 64 MB
Submit: 1528   Solved: 654
[ Submit][ Status][ Discuss]

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

Sample Output

4
1

HINT

注意旋转命令旋转“珠子”但不改变“位置”的编号,而反转命令始终以位置 1 为对称轴。例如当 N=10 时,项

链上的位置编号如图1:



但注意此时项链上的位置编号仍然如图1所示,于是翻转的对称轴不变。因而再执行一次“F”命令时,项链的颜色

如图4所示。

2. 关于CountSegment命令CS命令表示查询一个“线段”中有多少个“部分”。尤其注意当查询的长度

等于 N 时,我们仍然将查询部分作为“线段”理解。例如在图4所示的情况中,执行“CS 1 10”命令,查询从位

置 1 开始到位置 10 结束的这个长度为 10 的线段中有多少个“部分”,于是得到返回值 3 。与之形成对照的是

,若执行“C”命令,返回值则为 2

Source

[ Submit][ Status][ Discuss]

题解:平衡树

F 对[2,n]打翻转标记,注意交换左右子树的时候维持的左右端点的颜色也要交换

R 将后面k个元素插入到1的前面

S 交换两个点的颜色,把两个点splay到根,更新他所有祖先节点的信息

P 注意染色的时候可能需要分成两段

C 注意判断1,n两个节点的颜色是否相同,相同且颜色数!=1的话颜色段数要-1

CS 可能需要分两段统计答案,和在一起的时候判断1,n的颜色是否相同,相同的话答案-1

总之注意细节应该就没什么问题了,find的时候记得要标记下放。

#include<iostream>  
#include<cstdio>  
#include<algorithm>  
#include<cstring>  
#include<cmath>  
#define N 500033  
using namespace std;  
int fa[N],ch[N][2],val[N],ls[N],rs[N],tr[N],cover[N],delta[N],size[N];  
int c,n,q,a[N],root,cnt;  
void update(int now)  
{ 
    ls[0]=rs[0]=-2;  
    int l=ch[now][0]; int r=ch[now][1];  tr[now]=1;
    ls[now]=(l?ls[l]:val[now]); rs[now]=(r?rs[r]:val[now]);  
    size[now]=size[l]+size[r]+1;  
    if (l)  tr[now]+=tr[l];  
    if (r)  tr[now]+=tr[r];  
    if (rs[l]==val[now]||ls[r]==val[now]) tr[now]--;
    if (rs[l]==val[now]&&ls[r]==val[now]) tr[now]--;
}  
void change(int now)  
{  
    swap(ch[now][0],ch[now][1]);  
    swap(ls[now],rs[now]);  
    delta[now]^=1;  
}  
void color(int now,int c)
{
	val[now]=ls[now]=rs[now]=c;
	cover[now]=c; tr[now]=1;
}
void pushdown(int now)  
{  
    int l=ch[now][0],r=ch[now][1];  
    if(delta[now]) {  
        change(l); change(r);  
        delta[now]=0;  
    }  
    if (cover[now]) {  
        color(l,cover[now]); color(r,cover[now]);
        cover[now]=0;  
    }  
}  
int get(int x)  
{  
    return ch[fa[x]][1]==x;  
}  
void rotate(int x)  
{  
    int y=fa[x]; int z=fa[y];  
    pushdown(y); pushdown(x);  
    int which=get(x);  
    ch[y][which]=ch[x][which^1]; fa[ch[x][which^1]]=y;  
    ch[x][which^1]=y; fa[y]=x;  
    if (z) ch[z][ch[z][1]==y]=x;  
    fa[x]=z;  
    update(y); update(x);  
}  
void splay(int x,int tar)  
{  
    for (int f;(f=fa[x])!=tar;rotate(x))  
     if (fa[f]!=tar) rotate(get(f)==get(x)?f:x);  
    if (!tar) root=x;  
}  
int find(int x)  
{  
    int now=root;  
    while (true){  
        pushdown(now);  
        if (size[ch[now][0]]>=x) now=ch[now][0];  
        else {  
            x-=size[ch[now][0]];  
            if(x==1) return now;  
            x--; now=ch[now][1];  
        }  
    }  
}  
int build(int l,int r)  
{  
    int now;  
    if (l>r) return 0;  
    if (l==r) {  
        now=++cnt; val[now]=ls[now]=rs[now]=a[l];  
        tr[now]=1; size[now]=1; return now;  
    }  
    int mid=(l+r)/2;  
    now=++cnt;  val[now]=a[mid];
    ch[now][0]=build(l,mid-1);  
    ch[now][1]=build(mid+1,r);  
    fa[ch[now][0]]=now; fa[ch[now][1]]=now;  
    update(now);  
    return now;  
}  
int main()  
{  
    freopen("a.in","r",stdin);
    freopen("my.out","w",stdout);
    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);  
    scanf("%d",&q);  
    for (int i=1;i<=q;i++) {  
        char s[10]; scanf("%s",s+1);  
        int len=strlen(s+1);
        if (s[1]=='R') {  
            int k; scanf("%d",&k); int t=n-k+1;  
            int aa=find(t);  
            int bb=find(n+2);  
           // cout<<aa<<" "<<bb<<endl;
            splay(aa,0); 
			splay(bb,aa);  
            t=ch[ch[root][1]][0];  fa[t]=0;
            ch[ch[root][1]][0]=0; update(ch[root][1]); update(root);  
            aa=find(1); 
			bb=find(2);  
            splay(aa,0); splay(bb,aa);  
            ch[ch[root][1]][0]=t; fa[t]=ch[root][1];  
            update(ch[root][1]); update(root);  
        }  
        if (s[1]=='F') {  
            int aa=find(2); int bb=find(n+2);  
            splay(aa,0); splay(bb,aa);  
            int t=ch[ch[root][1]][0];  
            change(t);  update(ch[root][1]); update(root);
        }  
        if (s[1]=='S') {  
            int x,y; scanf("%d%d",&x,&y);  
            //timely update  
			int aa=find(x+1); int bb=find(y+1);
			swap(val[aa],val[bb]);
			splay(aa,0);
			splay(bb,0);  
        }  
        if (s[1]=='P') {
        	int l,r,c; scanf("%d%d%d",&l,&r,&c); 
        	if (l<=r) {
	        	int aa=find(l); int bb=find(r+2);
	        	splay(aa,0); splay(bb,aa);
	        	color(ch[ch[root][1]][0],c);
	        	update(ch[root][1]); update(root);
            }
            else {
            	int aa=find(1); int bb=find(r+2);
            	splay(aa,0); splay(bb,aa);
            	color(ch[ch[root][1]][0],c);
	        	update(ch[root][1]); update(root);
	        	aa=find(l); bb=find(n+2);
	        	splay(aa,0); splay(bb,aa);
            	color(ch[ch[root][1]][0],c);
	        	update(ch[root][1]); update(root);
			}
		}
		if (s[1]=='C'&&len==1) {
		 int aa=find(2); int bb=find(n+1);
		 int ans=tr[root]-2;
		 if (ans>1&&val[aa]==val[bb]) ans--;
		 printf("%d\n",ans);
	    }
		if (s[1]=='C'&&s[2]=='S') {
			int l,r; scanf("%d%d",&l,&r); 
			if (l<=r) {
				int aa=find(l); int bb=find(r+2);
				splay(aa,0); splay(bb,aa);
				printf("%d\n",tr[ch[ch[root][1]][0]]);
		    }
		    else {
		    	int aa=find(1); int bb=find(r+2);
		    	splay(aa,0); splay(bb,aa); 
		    	int ans=tr[ch[ch[root][1]][0]];
		    	aa=find(l); bb=find(n+2);
		    	splay(aa,0); splay(bb,aa);
		    	ans+=tr[ch[ch[root][1]][0]];
		    	aa=find(2);  bb=find(n+1);
		    	if (val[aa]==val[bb]) ans--;
		    	printf("%d\n",ans);
			}
		}
    }  
}  




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值