HDU 4453 Looploop(伸展树应用,数列环)

题意:

            给定一个环,和一个原点,对这个环有以下操作:

add x 操作:从队首开始的的连续k2个数都加上x.

reverse 操作: 从队首开始的连续k1个数都翻转

insert x 操作:在第一个元素与第二个元素之间插入一个x

delete 操作: 删除原点,新原点顺时针移动一下

move 1操作:原点逆时针移动一个

move 2操作: 原点顺时针移动一个

query 操作: 返回原点元素的值

题解:

      伸展树的应用:

正常的伸展树是对数列进行操作,而本题可看作是对一个首尾相连的数列进行操作;标记源点的位置,每次addreverse的时候,只需将源点反转至根节点,把根节点左边的删除,再插入到剩余序列的尾部,然后再进行更新即可。


#include<bits/stdc++.h>

using namespace std;

const int maxn = 2e5+99;
#define keyv ch[ch[root][1]][0]
int pre[maxn],sz[maxn],rev[maxn],add[maxn],ch[maxn][2];
int root,tot1,key[maxn];
int tot2,s[maxn];
int tp;
int n,q,k1,k2;
int a[maxn];

void newnode(int &r,int fa,int k)
{
    if(tot2) r = s[tot2--];
    else r = ++tot1;
    key[r] = k;
    pre[r] = fa;
    add[r] = rev[r] = ch[r][0] = ch[r][1] = 0;
    sz[r] = 1;
}

void update_rev(int r)
{
    if(!r)return;
    swap(ch[r][0],ch[r][1]);
    rev[r]^=1;
}

void update_add(int r,int v)
{
    if(!r)return;
    key[r] += v;
    add[r] += v;
}


void pushup(int r)
{
    sz[r] = 1 + sz[ch[r][1]]+sz[ch[r][0]];
}


void pushdown(int r)
{
    if(add[r])
    {
        update_add(ch[r][0],add[r]);
        update_add(ch[r][1],add[r]);
        add[r] = 0;
    }
    if(rev[r])
    {
        update_rev(ch[r][0]);
        update_rev(ch[r][1]);
        rev[r] = 0;
    }
}
void build(int &x,int l,int r,int fa)
{
    if(l>r)return;
    int mid = (l+r)>>1;
    newnode(x,fa,a[mid]);
    build(ch[x][0],l,mid-1,x);
    build(ch[x][1],mid+1,r,x);
    pushup(x);
}



void init()
{
    root = tot1=tot2 = 0;
    pre[root] = sz[root] = rev[root] = add[root] = key[root] = ch[root][0] = ch[root][1] = 0;
    newnode(root,0,-1);
    newnode(ch[root][1],root,-1);
    for(int i=0;i<n;i++)scanf("%d",a+i);
    build(keyv,0,n-1,ch[root][1]);
    pushup(ch[root][1]);
    pushup(root);
}


void rotate(int x,int d)
{
    int y = pre[x];
    pushdown(y),pushdown(x);
    ch[y][!d] = ch[x][d];
    pre[ch[x][d]] = y;
    if(pre[y]) ch[pre[y]][ch[pre[y]][1]==y]=x;
    pre[x] = pre[y];
    ch[x][d] = y;
    pre[y] = x;
    pushup(y);
}

void splay(int r,int goal)
{
    while(pre[r] != goal)
    {
        if(pre[pre[r]]==goal)
        {
            rotate(r,ch[pre[r]][0]==r);
        }
        else
        {
            int y = pre[r];
            int d = ch[pre[y]][0] == y;
            if(ch[y][d]==r)
            {
                rotate(r,!d);
                rotate(r,d);
            }
            else
            {
                rotate(y,d);
                rotate(r,d);
            }
        }
    }
    pushup(r);
    if(goal==0)root = r;
}


int getkth(int r,int k)
{
    pushdown(r);
    //cout<<1;
    int t = sz[ch[r][0]]+1;
    if(k==t) return r;
    else if(k<t)return getkth(ch[r][0],k);
    else return getkth(ch[r][1],k-t);
}

void ADD(int x)
{
    splay(tp,0);///删除左边的
    int tmp = sz[ch[root][0]]+1;
    splay(getkth(root,1),0);
    splay(getkth(root,tmp),root);
    tmp = keyv;
    keyv = 0;
    pushup(ch[root][1]);
    pushup(root);

    ///添加至末尾
    splay(getkth(root,sz[root]-1),0);
    keyv = tmp;
    pre[keyv] = ch[root][1];
    pushup(ch[root][1]);
    pushup(root);

    ///更新
    splay(getkth(root,1),0);
    splay(getkth(root,k2+2),root);
    update_add(keyv,x);
    pushup(ch[root][1]);
    pushup(root);

    tp = getkth(root,2);
}

void REVERSE()
{
    splay(tp,0);
    int tmp = sz[ch[root][0]]+1;
    splay(getkth(root,1),0);
    splay(getkth(root,tmp),root);
    tmp = keyv;
    keyv = 0;
    pushup(ch[root][1]);
    pushup(root);

    splay(getkth(root,sz[root]-1),0);
    keyv = tmp;
    pre[keyv] = ch[root][1];
    pushup(ch[root][1]);
    pushup(root);


    splay(getkth(root,1),0);
    splay(getkth(root,k1+2),root);
    update_rev(keyv);
    pushup(ch[root][1]);
    pushup(root);

    tp = getkth(root,2);
}


void insert(int x)
{
    splay(tp,0);
    int t = sz[ch[root][0]]+2;
    splay(getkth(root,t),root);
    newnode(keyv,ch[root][1],x);
    pushup(ch[root][1]);
    pushup(root);
}

void DELETE()
{
    splay(tp,0);
    int tmp = sz[ch[root][0]];
    splay(getkth(root,tmp),0);
    splay(getkth(root,tmp+2),root);

    s[++tot2] = keyv;
    keyv = 0;
    pushup(ch[root][1]);
    pushup(root);
    ///给顺时针的下一个
    if(tmp+1 == sz[root])tp = getkth(root,2);///右边没了(顺时针没了)
    else tp = getkth(root,tmp+1);
}

void MOVE(int x)
{
    if(x==1)///逆时针
    {
        splay(tp,0);
        int t = sz[ch[root][0]];
        if(t==1)t = sz[root]-1;///如果左边没了
        tp = getkth(root,t);
    }
    else///顺时针
    {
        splay(tp,0);
        int t = sz[ch[root][0]]+2;
        if(t == sz[root])t=2;///如果右边没了
        tp = getkth(root,t);
    }
}


int query()
{
    splay(tp,0);
    return key[root];
}

char op[99];
int x;
int main()
{
    int kase = 0;
    while(cin>>n>>q>>k1>>k2)
    {
        if(!n && !q && !k1 && !k2)break;
        printf("Case #%d:\n",++kase);
        init();
        tp = getkth(root,2);
        while(q--)
        {
            scanf("%s",op);
            if(op[0] == 'a')
            {
                scanf("%d",&x);
                ADD(x);
            }
            else if(op[0] == 'r')
            {
                REVERSE();
            }
            else if(op[0]=='i')
            {
                scanf("%d",&x);
                insert(x);
            }
            else if(op[0] == 'd')
                DELETE();
            else if(op[0]=='m')
            {
                scanf("%d",&x);
                MOVE(x);
            }
            else printf("%d\n",query());
        }
    }
}





























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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值