[BZOJ1493][NOI2007]项链工厂(splay)

本文介绍了一种使用树状数组实现复杂操作的方法,包括旋转、查找等,并通过具体的代码示例展示了如何进行区间更新、懒惰传播等操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

传送门

题解

好久没写数据结构了
维护size、有几段sum、最左边和最右边的颜色lc和rc
需要注意的几个地方:
1、因为在开始和结尾插入了点,注意find的编号问题
2、所有标记都是对当前点已经做过但是对儿子并没有做过
3、交换的时候要同时交换lc和rc
4、提取区间之后要将根的右儿子和根都update
5、rotate和find的时候不要忘了update和pushdown
6、如果一个环只有一种颜色需要特判,也就是ans=max(ans,1)

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define N 500005

int n,c,root,q,k,l,r,x,ans;
char opt[5];
int f[N],ch[N][2],color[N],size[N],lc[N],rc[N],sum[N],rev[N],delta[N];

void update(int x)
{
    size[x]=1;
    lc[x]=rc[x]=color[x];
    sum[x]=1;
    if (ch[x][0])
    {
        size[x]+=size[ch[x][0]];
        lc[x]=lc[ch[x][0]];
        sum[x]+=sum[ch[x][0]];
        if (rc[ch[x][0]]==color[x]) --sum[x];
    }
    if (ch[x][1])
    {
        size[x]+=size[ch[x][1]];
        rc[x]=rc[ch[x][1]];
        sum[x]+=sum[ch[x][1]];
        if (lc[ch[x][1]]==color[x]) --sum[x];
    }
}
void pushdown(int x)
{
    int l=ch[x][0],r=ch[x][1];
    if (rev[x])
    {
        if (l)
        {
            rev[l]^=1;
            swap(ch[l][0],ch[l][1]);
            swap(lc[l],rc[l]);
        }
        if (r)
        {
            rev[r]^=1;
            swap(ch[r][0],ch[r][1]);
            swap(lc[r],rc[r]);
        }
        rev[x]=0;
    }
    if (delta[x])
    {
        if (l) color[l]=lc[l]=rc[l]=delta[l]=delta[x],sum[l]=1;
        if (r) color[r]=lc[r]=rc[r]=delta[r]=delta[x],sum[r]=1;
        delta[x]=0;
    }
}
int build(int l,int r,int fa)
{
    if (l>r) return 0;
    int mid=(l+r)>>1;
    f[mid]=fa;
    int ls=build(l,mid-1,mid);
    int rs=build(mid+1,r,mid);
    ch[mid][0]=ls,ch[mid][1]=rs;
    update(mid);
    return mid;
}
int get(int x)
{
    return ch[f[x]][1]==x;
}
void rotate(int x)
{
    int old=f[x],oldf=f[old],wh=get(x);
    pushdown(old);
    pushdown(x);
    ch[old][wh]=ch[x][wh^1];
    if (ch[old][wh]) f[ch[old][wh]]=old;
    ch[x][wh^1]=old;
    f[old]=x;
    if (oldf) ch[oldf][ch[oldf][1]==old]=x;
    f[x]=oldf;
    update(old);
    update(x);
}
void splay(int x,int tar)
{
    for (int fa;(fa=f[x])!=tar;rotate(x))
        if (f[fa]!=tar)
            rotate((get(x)==get(fa))?fa:x);
    if (!tar) root=x;
}
int find(int x)
{
    int now=root;
    while (1)
    {
        pushdown(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 (x<=tmp) return now;
            x-=tmp;
            now=ch[now][1];
        }
    }
}
int main()
{
    scanf("%d%d",&n,&c);
    for (int i=2;i<=n+1;++i) scanf("%d",&color[i]);
    color[1]=color[n+2]=c+1;
    root=build(1,n+2,0);
    scanf("%d",&q);
    while (q--)
    {
        scanf("%s",opt);
        if (opt[0]=='R')
        {
            scanf("%d",&k);
            // n-k+1 n
            int aa=find(n-k+1);
            int bb=find(n+2);
            splay(aa,0);
            splay(bb,aa);
            int now=ch[ch[root][1]][0];
            ch[ch[root][1]][0]=0;
            update(ch[root][1]);
            update(root);

            // 0 1
            int cc=find(1);
            int dd=find(2);
            splay(cc,0);
            splay(dd,cc);
            ch[ch[root][1]][0]=now;
            f[now]=ch[root][1];
            update(ch[root][1]);
            update(root);
        }
        if (opt[0]=='F')
        {
            if (n<=2) continue;
            // 2 n
            int aa=find(2);
            int bb=find(n+2);
            splay(aa,0);
            splay(bb,aa);
            int now=ch[ch[root][1]][0];
            swap(ch[now][0],ch[now][1]);
            swap(lc[now],rc[now]);
            rev[now]^=1;
        }
        if (opt[0]=='S')
        {
            scanf("%d%d",&l,&r);
            int aa=find(l+1);
            int bb=find(r+1);
            swap(color[aa],color[bb]);
            splay(aa,0);
            splay(bb,0);
        }
        if (opt[0]=='P')
        {
            scanf("%d%d%d",&l,&r,&x);
            if (l<=r)
            {
                // l r
                int aa=find(l);
                int bb=find(r+2);
                splay(aa,0);
                splay(bb,aa);
                int now=ch[ch[root][1]][0];
                color[now]=lc[now]=rc[now]=x;
                sum[now]=1;
                delta[now]=x;
                update(ch[root][1]);
                update(root);
            }
            else
            {
                // l n
                int aa=find(l);
                int bb=find(n+2);
                splay(aa,0);
                splay(bb,aa);
                int now=ch[ch[root][1]][0];
                color[now]=lc[now]=rc[now]=x;
                sum[now]=1;
                delta[now]=x;
                update(ch[root][1]);
                update(root);

                // 1 r
                int cc=find(1);
                int dd=find(r+2);
                splay(cc,0);
                splay(dd,cc);
                now=ch[ch[root][1]][0];
                color[now]=lc[now]=rc[now]=x;
                sum[now]=1;
                delta[now]=x;
                update(ch[root][1]);
                update(root);
            }
        }
        if (opt[0]=='C')
            if (opt[1]=='S')
            {
                scanf("%d%d",&l,&r);
                if (l<=r)
                {
                    // l r
                    int aa=find(l);
                    int bb=find(r+2);
                    splay(aa,0);
                    splay(bb,aa);
                    int now=ch[ch[root][1]][0];
                    ans=sum[now];
                    if (l==1&&r==n&&lc[now]==rc[now]) --ans;
                    ans=max(ans,1);
                    printf("%d\n",ans);
                }
                else
                {
                    // l n
                    int aa=find(l);
                    int bb=find(n+2);
                    splay(aa,0);
                    splay(bb,aa);
                    ans=sum[ch[ch[root][1]][0]];

                    // 1 r
                    int cc=find(1);
                    int dd=find(r+2);
                    splay(cc,0);
                    splay(dd,cc);
                    ans+=sum[ch[ch[root][1]][0]];
                    // 1 n
                    int ee=find(2);
                    int ff=find(n+1);
                    if (color[ee]==color[ff]) --ans;
                    ans=max(ans,1);
                    printf("%d\n",ans);
                }
            }
            else
            {
                int aa=find(1);
                int bb=find(n+2);
                splay(aa,0);
                splay(bb,aa);
                int now=ch[ch[root][1]][0];
                ans=sum[now];
                if (lc[now]==rc[now]) --ans;
                ans=max(ans,1);
                printf("%d\n",ans);
            }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值