BZOJ1493: [NOI2007]项链工厂 Splay

1493: [NOI2007]项链工厂

Time Limit: 30 Sec   Memory Limit: 64 MB
Submit: 1434   Solved: 622
题解:
一个环上有各种颜色珠子,支持6种操作:
1.区间平移(把原题的意思转化一下就成了区间平移)
2.区间翻转
3.交换两个珠子的位置
4.区间染色
5.查询整个环上有多少个颜色区间
6.查询一段区间有多少个颜色
一看就是Splay,做做做
交换两个珠子的位置刚开始写麻烦了,我硬把两个珠子的位置进行了交换,其实不难发现只要把这两个珠子Splay到root和rs[root]然后直接交换颜色,Pushup一下两个点就好了。
Pushup(x):
如果x和两侧都相同,颜色段数等于左右儿子之和-1
如果只有一侧相同,颜色段数等于左右儿子之和
若都不同,颜色段数等于左右儿子+1
至于区间操作的4,6,都有可能出现l>r的情况,对于l>r的情况,分成(l,n),(1,r)两段处理
注意统计颜色段数的5操作,判断一下1和n的颜色是否相同,相同ans-1 

#pragma GCC optimize ("O2") 
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=500005;
int n,m,q,ls[N],rs[N],fa[N],siz[N],rev[N],cov[N],lc[N],rc[N],sc[N],c[N],rt;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void Pushup(int x)
{
	siz[x]=siz[ls[x]]+siz[rs[x]]+1;
	if(ls[x]) lc[x]=lc[ls[x]];
	else lc[x]=c[x];
	if(rs[x]) rc[x]=rc[rs[x]];
	else rc[x]=c[x];
	if(rc[ls[x]]==c[x]&&c[x]==lc[rs[x]]) sc[x]=sc[ls[x]]+sc[rs[x]]-1;
	else if(rc[ls[x]]==c[x]||c[x]==lc[rs[x]]) sc[x]=sc[ls[x]]+sc[rs[x]];
	else sc[x]=sc[ls[x]]+sc[rs[x]]+1;
}
void Prev(int x)
{
	if(!x) return;
	swap(ls[x],rs[x]);
	swap(lc[x],rc[x]);
	rev[x]^=1;
}
void Pcov(int x,int v)
{
	if(!x) return;
	lc[x]=rc[x]=c[x]=v;
	sc[x]=1;
	cov[x]=v;
}
void Pushdown(int x)
{
	if(rev[x])
	{
		Prev(ls[x]),Prev(rs[x]);
		rev[x]=0;
	}
	if(cov[x]!=1e9)
	{
		Pcov(ls[x],cov[x]),Pcov(rs[x],cov[x]);
		cov[x]=1e9;
	}
}
void Rotate(int x,int &k)
{
	int y=fa[x],z=fa[y];
	if(k==y) k=x;
	else
	{
		if(y==ls[z]) ls[z]=x;
		else rs[z]=x;
	}
	fa[y]=x;
	fa[x]=z;
	if(x==ls[y]) ls[y]=rs[x],fa[rs[x]]=y,rs[x]=y;
	else rs[y]=ls[x],fa[ls[x]]=y,ls[x]=y;
	Pushup(y);
	Pushup(x);
}
void Splay(int x,int &k)
{
	while(x!=k)
	{
		int y=fa[x],z=fa[y];
		if(y!=k)
		{
			if(ls[y]==x^ls[z]==y) Rotate(x,k);
			else Rotate(y,k);
		}
		Rotate(x,k);
	}
}
int Find(int x,int rank)
{
	Pushdown(x);
	if(rank<=siz[ls[x]]) return Find(ls[x],rank);
	else if(rank==siz[ls[x]]+1) return x;
	else return Find(rs[x],rank-siz[ls[x]]-1);
}
void Build(int l,int r,int f)
{
	if(l>r) return;
	if(l==r)
	{
		siz[l]=1;
		lc[l]=rc[l]=c[l];
		sc[l]=1;
		fa[l]=f;
		if(l<f) ls[f]=l;
		else rs[f]=l;
		return;
	}
	int mid=(l+r)>>1;
	Build(l,mid-1,mid);
	Build(mid+1,r,mid);
	Pushup(mid);
	fa[mid]=f;
	if(mid<f) ls[f]=mid;
	else rs[f]=mid;
}
int Make(int x,int y)
{
	x=Find(rt,x),y=Find(rt,y+2);
	Splay(x,rt);
	Splay(y,rs[x]);
	return ls[y];
}
int x,y,l,r,k,v;
void Trans()
{
	k=read();
	x=Make(1,n-k);
	ls[fa[x]]=0;
	Pushup(fa[x]);
	Pushup(fa[fa[x]]);
	l=Find(rt,k+1);
	r=Find(rt,k+2);
	Splay(l,rt);
	Splay(r,rs[l]);
	ls[r]=x;
	fa[x]=r;
	Pushup(r);
	Pushup(fa[r]);
}
void Reverse()
{
	if(n<=2) return;
	x=Make(2,n);
	Prev(x);
	Pushup(fa[x]);
	Pushup(fa[fa[x]]);
}
void Swap()
{
	l=read(),r=read();
	if(l==r) return;
	if(l>r) swap(l,r);
	l=Find(rt,l+1);
	r=Find(rt,r+1);
	Splay(l,rt);
	Splay(r,rs[l]);
	swap(c[l],c[r]);
	Pushup(l);
	Pushup(r);
}
void Cover()
{
	l=read(),r=read(),v=read();
	if(l<=r)
	{
		x=Make(l,r);
		Pcov(x,v);
		Pushup(fa[x]);
		Pushup(fa[fa[x]]);
	}
	else
	{
		x=Make(l,n);
		Pcov(x,v);
		Pushup(fa[x]);
		Pushup(fa[fa[x]]);
		x=Make(1,r);
		Pcov(x,v);
		Pushup(fa[x]);
		Pushup(fa[fa[x]]);
	}
}
int Qall()
{
	x=Make(1,n);
	int ret=sc[x];
	if(ret>1&&c[Find(rt,2)]==c[Find(rt,n+1)]) ret--;
	return ret;
}
int Qsome()
{
	x=read(),y=read();
	if(x<=y)
	{
		x=Make(x,y);
		return sc[x];
	}
	else
	{
		int now=0;
		x=Make(x,n),now+=sc[x];
		x=Make(1,y),now+=sc[x];
		if(c[Find(rt,2)]==c[Find(rt,n+1)]) now--;
		return now;
	}
}
int main()
{
	n=read(),m=read();
	for(int i=1;i<N;i++) cov[i]=1e9;
	for(int i=2;i<=n+1;i++) c[i]=read();
	c[0]=c[1]=c[n+2]=1e9;
	rt=(n+3)>>1;
	Build(1,n+2,0);
	q=read();
	char c[15];
	while(q--)
	{
		scanf("%s",c);
		if(c[0]=='R') Trans();
		else if(c[0]=='F') Reverse();
		else if(c[0]=='S') Swap();
		else if(c[0]=='P') Cover();
		else if(c[1]=='S') printf("%d\n",Qsome());
		else printf("%d\n",Qall());
	}
}



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]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值