hdu 4453 Looploop 伸展树splay

给一列数构成一个环,一个指针初始指向某个位置,两个参数k1,k2。有6种操作:

add x 从指针指向位置开始,连续k2个数分别加上x;

        reverse 从指针开始连续k1个数,反转位置.

        insert  x 在指针指向位置的后面添加一个数x

        delete  删除当前指针指向的数

        move x  x==1时,指针前移一位,x==2时,指针后移一位。

        query 输出指针当前指向的数。


        明显都是伸展数的基本操作,思路上应该没什么问题,就是写起来各种郁闷-...为了方便先添加两个虚拟节点,表示第一位的左边和最后一位的右边,接下来在这两个节点直接插入。指针指向的节点实质就是伸展树中rang==2的节点,这样在add,reverse的时候,找到最左侧的节点并将其伸展到根,再找到rank为k1+1或者k2+1的节点,伸展到根的下面,这样两节点之间的部分就是要操作的部分。move的话,前移就删掉虚拟首节点下一个节点,再插入到虚拟尾节点的前边,后移也一样。思路挺好想,就是代码写起来太烦了....

        

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <memory.h>
#include <cmath>
#include <string>
#include <cstring>
#include <queue>
#include <map>
#include <stack>
using namespace std;
typedef long long ll;
const int maxn=410000+1000;
int pre[maxn],ch[maxn][2];
int size[maxn],key[maxn];
int add[maxn],flip[maxn];
int root,n;
int tot;
int m,p,q,r,t,tt;
int k1,k2;
int a[maxn];
struct splaytree
{
    void pushup(int r)
    {
        size[r]=1+size[ch[r][0]]+size[ch[r][1]];
    }
    void go_f(int r)
    {
        flip[r]^=1;
        swap(ch[r][0],ch[r][1]);
    }
    void go_a(int r,int c)
    {
        add[r]+=c;
        key[r]+=c;
    }
    void pushdown(int r)
    {
         if (add[r])
        {
//            key[r]+=add[r];
//            add[ch[r][0]]+=add[r];
//            add[ch[r][1]]+=add[r];
            go_a(ch[r][0],add[r]);
            go_a(ch[r][1],add[r]);
            add[r]=0;
        }
        if (flip[r])
        {
//            flip[ch[r][0]]^=flip[r];
//            flip[ch[r][1]]^=flip[r];
//            swap(ch[r][0],ch[r][1]);
            go_f(ch[r][0]);
            go_f(ch[r][1]);
            flip[r]=0;
        }

    }
    void rotate(int x,int kind)
    {
        int y=pre[x];
        pushdown(y);
        pushdown(x);
        ch[y][!kind]=ch[x][kind];
        pre[ch[x][kind]]=y;
        if (pre[y])
        {
            ch[pre[y]][ch[pre[y]][1]==y]=x;
        }
        pre[x]=pre[y];
        ch[x][kind]=y;
        pre[y]=x;
        pushup(y);
        pushup(x);
    }
    void splay(int x,int tgt)
    {
        pushdown(x);
        while(pre[x]!=tgt)
        {
            int y=pre[x];
            pushdown(pre[y]);
            pushdown(y);
            pushdown(x);
            if (pre[pre[x]]==tgt)
            {
                rotate(x,ch[pre[x]][0]==x);
            }
            else
            {
                int kind=ch[pre[y]][0]==y;
                if (ch[y][kind]==x)
                {
                    rotate(x,kind^1);
                    rotate(x,kind);
                }
                else
                {
                    rotate(y,kind);
                    rotate(x,kind);
                }
            }
        }
        pushup(x);
        if (tgt==0) root=x;
    }
    void select(int k,int tgt)
    {
        int rt=root;
        pushdown(rt);
        while(true)
        {
            if (k<=size[ch[rt][0]]) rt=ch[rt][0];
            else  if (k==size[ch[rt][0]]+1) break;
            else k-=(size[ch[rt][0]]+1),rt=ch[rt][1];
            pushdown(rt);
        }

        splay(rt,tgt);
    }
    void newnode(int &r,int father,int k)
    {
        r=++tot;
        pre[r]=father;
        size[r]=1;
        flip[r]=add[r]=0;
        key[r]=k;
        ch[r][0]=ch[r][1]=0;
    }
    void build(int l,int r,int &x,int rt)
    {
        if (l>r) return;
        int m=(l+r)>>1;
        newnode(x,rt,a[m]);
        build(l,m-1,ch[x][0],x);
        build(m+1,r,ch[x][1],x);
        pushup(x);
    }
    void init()
    {
        tot=root=0;
        newnode(root,0,0);
        newnode(ch[root][1],root,0);
        build(0,n-1,ch[ch[root][1]][0],ch[root][1]);
        pushup(ch[root][1]);
        pushup(root);
    }
    void Add(int c)
    {
        select(1,0);
        select(k2+2,root);
//        add[ch[ch[root][1]][0]]+=c;
        go_a(ch[ch[root][1]][0],c);
    }
    void Filp()
    {
        select(1,0);
        select(k1+2,root);
//        flip[ch[ch[root][1]][0]]^=1;
        go_f(ch[ch[root][1]][0]);
    }
    int del(int tp)
    {
        int &rt=root;
        int len=0;
        len=size[rt];
        int val;
        if (tp)
        {
            select(1,0);
            select(3,rt);
            val=key[ch[ch[rt][1]][0]];
            ch[ch[rt][1]][0]=0;
            pushup(ch[rt][1]);
            pushup(rt);
        }
        else
        {
            select(len-2,0);
            select(len,rt);
            val=key[ch[ch[rt][1]][0]];
            ch[ch[rt][1]][0]=0;
            pushup(ch[rt][1]);
            pushup(rt);
        }
        return val;
    }
    void insert(int val,int pos)
    {
        int &rt=root;
        select(pos,0);
        select(pos+1,rt);
        newnode(ch[ch[rt][1]][0],ch[rt][1],val);
        pushup(ch[rt][1]);
        pushup(rt);
    }
    void move(int tp)
    {
       int &rt=root;
       int val;
       int len;
       if (tp==2)
       {
         val=del(1);
         len=size[rt];
         insert(val,len-1);
       }
       else
       {
         val=del(0);
         insert(val,1);
       }
    }
    void query()
    {
        select(2,0);
        pushdown(root);
        printf("%d\n",key[root]);
    }
}spt;

int main()
{
//    freopen("in.txt","r",stdin);
    int tt=0;
    while(scanf("%d%d%d%d",&n,&m,&k1,&k2) && (n && m && k1 && k2))
    {
        tt++;
        printf("Case #%d:\n",tt);
        char cmd[20];
        int cd;
        for (int i=0; i<n; i++)
        scanf("%d",&a[i]);
        spt.init();
        for (int i=1; i<=m; i++)
        {
            scanf("%s",cmd);
            if (cmd[0]=='a')
            {
                scanf("%d",&cd);
                spt.Add(cd);
            }
            if (cmd[0]=='r')
            {
                spt.Filp();
            }
            if (cmd[0]=='i')
            {
                scanf("%d",&cd);
                spt.insert(cd,2);
            }
            if (cmd[0]=='d')
            {
                spt.del(1);
            }
            if (cmd[0]=='m')
            {
                scanf("%d",&cd);
                spt.move(cd);
            }
            if (cmd[0]=='q')
            {
                spt.query();
            }
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值