HDU 3487 Play with Chain


【分析】
哦艹一道模板题因为一些zz原因挂了一早上…还荒废了宝宝的数学课…事实证明还是劳逸结合最有效…orz

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

思路:对于cut操作我们需要先提取出区间[a,b]然后,先暂时分裂出去,然后以c为边界分裂左右两部分,然后合并左边的和区间[a,b],将最大的旋转至根,然后和右边的合并。对于filp操作,我们可以使用lazy标记,先不翻转,需要的时候再翻转。

mdzz数组还开小了几次…结果提示TLE而不是RE…哦艹


【代码】

//HDU 3487 Play with Chain
#include<iostream>
#include<cstring>
#include<cstdio>
#define inf 1e9+7
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=500005;
char c[10];
int n,m,sz,opt,cnt,root;
int f[mxn],ch[mxn][2],key[mxn],mark[mxn],size[mxn],data[mxn];
inline int read()
{ 
    int x=0,f=1;char tt=getchar();
    while(tt<'0'||tt>'9'){if(tt=='-')f=-1;tt=getchar();}
    while(tt>='0'&&tt<='9'){x=x*10+tt-'0';tt=getchar();}
    return x*f;
}
inline void clear(int x)
{
    f[x]=ch[x][0]=ch[x][1]=key[x]=size[x]=0;
}
inline int get(int x)   //左子树or右子树 
{
    if(ch[f[x]][0]==x) return 0;return 1;
}
inline void update(int x)
{
    size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
}
inline void pushdown(int x)
{
    if(x && mark[x]) 
    {
        mark[x]=0;
        if(ch[x][0]) mark[ch[x][0]]^=1;
        if(ch[x][1]) mark[ch[x][1]]^=1;
        swap(ch[x][0],ch[x][1]);
    }
}
inline void rotate(int x)
{
    pushdown(x);
    int fa=f[x],fafa=f[fa],which=get(x);
    ch[fa][which]=ch[x][which^1],f[ch[fa][which]]=fa;
    ch[x][which^1]=fa,f[fa]=x;
    f[x]=fafa;
    if(fafa) ch[fafa][ch[fafa][1]==fa]=x;
    update(fa),update(x);
}
inline void splay(int x,int lastfa)
{
    for(int fa;(fa=f[x])!=lastfa;rotate(x))
      if(f[fa]!=lastfa) rotate(get(x)==get(fa)?fa:x);
    if(!lastfa) root=x;
}
inline int number(int x)
{
    int now=root;
    while(1)
    {
        pushdown(now);
        if(x<=size[ch[now][0]]) now=ch[now][0];
        else
        {
            if(x==size[ch[now][0]]+1) return now;
            x=x-size[ch[now][0]]-1;
            now=ch[now][1];pushdown(now);
        }
    }
}
inline int build(int fa,int l,int r)
{
    if(l>r) return 0;
    int mid=l+r>>1,now=++sz;
    key[now]=data[mid],f[now]=fa,mark[now]=0;
    ch[now][0]=build(now,l,mid-1);
    ch[now][1]=build(now,mid+1,r);
    update(now);
    return now;
}
inline void print(int now)
{
    pushdown(now);
    if(ch[now][0]) print(ch[now][0]);
    if(key[now]>-inf && key[now]<inf)
    {
        printf("%d",key[now]);
        cnt++;
        if(cnt<n) printf(" ");
    }
    if(ch[now][1]) print(ch[now][1]);
}
//inline void debug(int now)
//{
//    if(ch[now][0]) debug(ch[now][0]);
//    printf("now=%d,key=%d\n",now,key[now]);
//    if(ch[now][1]) debug(ch[now][1]);
//}
int main()
{
//  freopen("rand.txt","r",stdin);
    int i,j,k,x,y,z;
    while(~scanf("%d%d",&n,&m) && n>=0 && m>=0)
    {
        M(f);M(key);M(mark);M(size);M(ch);
        sz=cnt=0;
        fo(i,1,n) data[i+1]=i;
        data[1]=-inf,data[n+2]=inf;
        root=build(0,1,n+2);
        fo(i,1,m) 
        {
            scanf("%s",c);
            if(c[0]=='C')   //切下并插入 
            {
                x=read(),y=read(),z=read();
                x++,y++,z++;
                x=number(x-1),y=number(y+1);
                splay(x,0),splay(y,x);
                int tmp=ch[ch[root][1]][0];
                ch[ch[root][1]][0]=0;
                update(ch[root][1]);
                int z1=number(z),z2=number(z+1);
                splay(z1,0),splay(z2,z1);
//                if(ch[ch[z1][1]][0]) return 0;
                ch[ch[root][1]][0]=tmp;
                f[tmp]=ch[root][1];
                update(ch[root][1]);
            }
            else   //翻转 
            {
                x=read(),y=read();
                x++,y++;
                x=number(x-1),y=number(y+1);
                splay(x,0);
                splay(y,x);
                mark[ch[ch[root][1]][0]]^=1; 
            }
        }
        print(root);
        printf("\n");
    }
    return 0;
}
/*
4 1 
CUT 1 2 1
8 2
CUT 3 5 4
FLIP 2 6
-1 -1
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值