[题解]bzoj1493 NOI2007项链工厂

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

Solution

显而易见的线段树或者Splay,Splay比较好打就打Splay了…
操作一就是截下Splay的后k个元素插到开头,操作二就是给区间2~N翻转,区间颜色段数就维护一下左右端点的颜色就可以合并了。注意特判整个区间颜色相同的情况。

#include<cstdio>
#include<algorithm>
using namespace std;

template<typename T>inline void read(T &x){
    T f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(x=0;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    x*=f;
}

const int maxn=500010;
struct Node{
    int ch[2],fa,col,cl,cr;
    int num,size,same;
    bool rev;
    Node(){ch[0]=ch[1]=fa=col=cl=cr=num=size=rev=same=0;}
}T[maxn];
int root,tot;

void update(int x){
    if(T[x].ch[0]&&T[x].ch[1]){
        T[x].cl=T[T[x].ch[0]].cl;
        T[x].cr=T[T[x].ch[1]].cr;
        T[x].num=T[T[x].ch[0]].num+T[T[x].ch[1]].num+1;
        T[x].size=T[T[x].ch[0]].size+T[T[x].ch[1]].size+1;
        if(T[T[x].ch[0]].cr==T[x].col)T[x].num--;
        if(T[T[x].ch[1]].cl==T[x].col)T[x].num--;
    }
    else if(T[x].ch[0]){
        T[x].cl=T[T[x].ch[0]].cl;
        T[x].cr=T[x].col;
        T[x].num=T[T[x].ch[0]].num+(T[T[x].ch[0]].cr!=T[x].col);
        T[x].size=T[T[x].ch[0]].size+1;
    }
    else if(T[x].ch[1]){
        T[x].cl=T[x].col;
        T[x].cr=T[T[x].ch[1]].cr;
        T[x].num=T[T[x].ch[1]].num+(T[T[x].ch[1]].cl!=T[x].col);
        T[x].size=T[T[x].ch[1]].size+1;
    }
    else{
        T[x].cl=T[x].cr=T[x].col;
        T[x].num=T[x].size=1;
    }
}
int Build(int *a,int l,int r,int fa=0){
    if(l>r)return 0;
    int x=++tot,mid=(l+r)>>1;
    T[x].col=a[mid];T[x].fa=fa;
    if(l==r){
        T[x].cl=T[x].cr=a[mid];
        T[x].num=T[x].size=1;
        return x;
    }
    T[x].ch[0]=Build(a,l,mid-1,x);
    T[x].ch[1]=Build(a,mid+1,r,x);
    return update(x),x;
}
void pushsame(int x,int c){
    T[x].col=T[x].cl=T[x].cr=T[x].same=c;
    T[x].num=1;T[x].rev=false;
}
void pushrev(int x){
    T[x].rev^=1;
    swap(T[x].cl,T[x].cr);
    swap(T[x].ch[0],T[x].ch[1]);
}
void pushdown(int x){
    if(T[x].same){
        pushsame(T[x].ch[0],T[x].same);
        pushsame(T[x].ch[1],T[x].same);
        T[x].same=0;
    }
    if(T[x].rev){
        pushrev(T[x].ch[0]);
        pushrev(T[x].ch[1]);
        T[x].rev=false;
    }
}
int getson(int x){
    return x==T[T[x].fa].ch[1];
}
void rotate(int x){
    int fa=T[x].fa,fafa=T[fa].fa,k=getson(x);
    pushdown(fa);pushdown(x);
    T[fa].ch[k]=T[x].ch[k^1];
    if(T[x].ch[k^1])T[T[x].ch[k^1]].fa=fa;
    T[T[T[x].ch[k^1]=fa].fa=x].fa=fafa;
    if(fafa)T[fafa].ch[fa==T[fafa].ch[1]]=x;
    update(fa);update(x);
}
void Splay(int x,int f=0){
    for(int fa;(fa=T[x].fa)!=f;rotate(x))
        if(T[fa].fa!=f)rotate(getson(x)==getson(fa)?fa:x);
    if(!f)root=x;
}
int Find(int rnk){
    int x=root;
    while(1){
        pushdown(x);
        if(T[x].ch[0]&&T[T[x].ch[0]].size>=rnk)x=T[x].ch[0];
        else{
            int temp=(T[x].ch[0]?T[T[x].ch[0]].size:0)+1;
            if(temp==rnk)return x;
            rnk-=temp;x=T[x].ch[1];
        }
    }
}

int n,m,c,a[maxn];

int main(){
    read(n);read(c);
    for(int i=1;i<=n;i++)read(a[i]);
    root=Build(a,1,n);
    read(m);
    while(m--){
        char opt[4];
        int l,r,k;
        scanf("%s",opt);
        if(opt[0]=='R'){
            read(k);
            Splay(Find(n-k));
            int temp=T[root].ch[1],fir=Find(1);
            T[root].ch[1]=0;update(root);
            T[T[temp].fa=fir].ch[0]=temp;
            update(fir);Splay(temp);
        }
        else if(opt[0]=='F'){
            Splay(Find(1));
            pushrev(T[root].ch[1]);
            update(root);
        }
        else if(opt[0]=='S'){
            read(l);read(r);
            int x=Find(l),y=Find(r);
            if(T[x].col==T[y].col)continue;
            int cx=T[x].col,cy=T[y].col;
            T[x].col=cy;update(x);Splay(x);
            T[y].col=cx;update(y);Splay(y);
        }
        else if(opt[0]=='P'){
            read(l);read(r);read(k);
            if(l<=r){
                if(l==1&&r==n)pushsame(root,k);
                else if(l==1)Splay(Find(r+1)),pushsame(T[root].ch[0],k),update(root);
                else if(r==n)Splay(Find(l-1)),pushsame(T[root].ch[1],k),update(root);
                else{
                    Splay(Find(l-1));Splay(Find(r+1),root);
                    pushsame(T[T[root].ch[1]].ch[0],k);
                    update(T[root].ch[1]);update(root);
                }
            }
            else{
                Splay(Find(l-1));pushsame(T[root].ch[1],k);update(root);
                Splay(Find(r+1));pushsame(T[root].ch[0],k);update(root);
            }
        }
        else if(opt[0]=='C'&&opt[1]=='\0'){
            int temp=T[root].num-(T[root].cl==T[root].cr);
            printf("%d\n",max(temp,1));
        }
        else if(opt[0]=='C'&&opt[1]=='S'){
            read(l);read(r);
            int temp=0;
            if(l<=r){
                if(l==1&&r==n)temp=T[root].num;
                else if(l==1)Splay(Find(r+1)),temp=T[T[root].ch[0]].num;
                else if(r==n)Splay(Find(l-1)),temp=T[T[root].ch[1]].num;
                else{
                    Splay(Find(l-1));Splay(Find(r+1),root);
                    temp=T[T[T[root].ch[1]].ch[0]].num;
                }
            }
            else{
                Splay(Find(l-1));temp+=T[T[root].ch[1]].num;
                Splay(Find(r+1));temp+=T[T[root].ch[0]].num;
                temp-=(T[root].cl==T[root].cr);
            }
            printf("%d\n",temp);
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值