hdu 3487 Play with Chain (区间翻转+区间切割)

题目

题意:开始有一个1-n的序列,进行m次操作,cut a b c将区间[a,b]取出得到新序列,将区间插入到新序列第c个元素之后。filp a b 将区间a,b翻转,输出最终的序列。

思路:现将a-b这个区间取出来,然后再来将c这个位置断开,然后合并左边的和区间[a,b],将最大的旋转至根,然后和右边的合并.

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e6;
const int inf=0x3f3f3f3f;
int sz,root;
int key[N],size[N],f[N],ch[N][2],lazy[N];
int n,m;
int a[N],ans[N];
int k;
bool get(int x)
{
    return ch[f[x]][1]==x;
}
void Modify(int x)
{
    if(!x)return;
    lazy[x]^=1;
}
void pushup(int x)
{
    size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
}
void pushdown(int x)
{
    if(lazy[x]&&x)
    {
        lazy[ch[x][0]]^=1;
        lazy[ch[x][1]]^=1;
        lazy[x]=0;
        swap(ch[x][0],ch[x][1]);
    }
}
void rotate(int x)
{
    int old=f[x],oldf=f[old],whichx=get(x);
    ch[old][whichx]=ch[x][whichx^1];
    f[ch[old][whichx]]=old;
    ch[x][whichx^1]=old;
    f[old]=x;
    f[x]=oldf;
    if(oldf)
        ch[oldf][ch[oldf][1]==old]=x;
    pushup(old);
    pushup(x);
}
void splay(int x,int goal)
{
    int y,z;
    pushdown(x);
    while(f[x]!=goal)
    {
        y=f[x],z=f[y];
        if(z==goal)
        {
            pushdown(y);
            pushdown(x);
            rotate(x);
        }
        else
        {
            pushdown(z);
            pushdown(y);
            pushdown(x);
            if((ch[z][0]==y) == (ch[y][0]==x)) rotate(y);
            else rotate(x);
        }
    }
    if(!goal)root=x;
}
int find(int x)
{
    int now=root;
    while(1)
    {
        pushdown(now);
        if(x<=size[ch[now][0]])now=ch[now][0];
        else
        {
            x-=size[ch[now][0]]+1;
            if(!x)return now;
            now=ch[now][1];
        }
    }
}
int pre()
{
    int now=root;
    pushdown(now);
    while(ch[now][1])
    {
        now=ch[now][1];
        pushdown(now);
    }
    return now;
}
int build(int l,int r,int x)
{
    if(l>r)return 0;
    int mid=(l+r)/2;
    int now=++sz;
    key[now]=a[mid];
    f[now]=x;
    lazy[now]=0;
    ch[now][0]=build(l,mid-1,now);
    ch[now][1]=build(mid+1,r,now);
    pushup(now);
    return now;
}
void init()
{
    sz=root=0;
    memset(key,0,sizeof(key));
    memset(lazy,0,sizeof(lazy));
    memset(size,0,sizeof(size));
    memset(ch,0,sizeof(ch));
    memset(f,0,sizeof(f));
    for(int i=2;i<=n+1;i++)
        a[i]=i-1;
    a[1]=-inf;
    a[n+2]=inf;
    root=build(1,n+2,0);
}
void turn(int l,int r)
{
    l=find(l);
    r=find(r+2);
    splay(l,0);
    splay(r,root);
}
void merge(int root1,int root2)/*root2接到root1右子树,要求root1无右子树*/
{
    ch[root1][1]=root2;
    f[root2]=root1;
}
void work(int l,int r,int c)//将一个区间放在某个位置之后
{
     turn(l,r);
     int root1=ch[ch[root][1]][0];
     ch[ch[root][1]][0]=0;
     pushup(ch[root][1]);
     pushup(root);
     splay(find(c+1),0);
     int root2=ch[root][1];
     merge(root,root1);
     pushup(root);
     splay(pre(),0);
     merge(root,root2);
     pushup(root);
}
void write(int now)
{
    pushdown(now);
    if(ch[now][0])write(ch[now][0]);
    if(key[now]!=-inf&&key[now]!=inf)ans[k++]=key[now];
    if(ch[now][1])write(ch[now][1]);
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        if(n==-1&&m==-1)break;
        init();
        char op[10];
        int L,R,C;
        while(m--)
        {
            scanf("%s%d%d",op,&L,&R);
            if(op[0]=='F')
            {
                turn(L,R);
                Modify(ch[ch[root][1]][0]);
            }
            else
            {
                scanf("%d",&C);
                work(L,R,C);
            }
        }
        k=1;
        write(root);
        for(int i=1;i<=n;i++)
        {
            if(i>1)printf(" ");
            printf("%d",ans[i]);
        }
        printf("\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/imzxww/article/details/81270197