hdu4453-Looploop(伸展树)

题目有很多图,不好粘贴。。。。。

 

题意:给出N个数和K1,K2的值,最开始指针指向第一个数,有6种操作

add x : 给前K2个数都增加x

reverse : 翻转前K1个数

insert x : 在所指的数右边(顺时针)插入一个数

delete x : 删除指针所指的这个数,并且指针向右移(顺时针)

move x : x=1则指向向左移(逆时针),为2向右移(顺时针)

query : 输出指针所指的数

 

解析:这题涉及到插入删除,和给一段区间加值,线段树不能增加删除,链表的话又不能快速的给一段区间加数,所以只能用伸展树了。伸展树支持的操作很多,既有线段树的特性也有链表的特性。但是写起来复杂,所以一般题目如果能用常用的数据结构解决的就不要用伸展树了。我不具体介绍伸展树,自己下去多学学再看这题会容易许多。

 

源代码

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int INF=1e9+7;
const int maxn=200005;
int A[maxn],cnt;  //A数组保存数,cnt是节点标号,我是用数组模拟的
struct treap
{
    treap* son[2];  //左右儿子
    int v,s,add,lazy;  //v是值,s是大小,add是懒惰标记增加的值,lazy是懒惰标记是否需要翻转
    treap(){ v=s=add=lazy=0; son[0]=son[1]=NULL; }
    treap(int nv);
    int rk(){ return son[0]->s+1; }  //排名,第几个数
    int cmp(int k)  //比较,如果相等返回-1,小于返回0,大于1
    {
        if(k==rk()) return -1;
        return k<rk()?0:1;
    }
    void pushup(){ s=son[0]->s+son[1]->s+1; }  //更新大小
    void pushdown()  //处理懒惰标记
    {
        if(lazy)
        {
            swap(son[0],son[1]);
            son[0]->lazy^=1;
            son[1]->lazy^=1;
            lazy=0;
        }
        if(add)
        {
            v+=add;
            son[0]->add+=add;
            son[1]->add+=add;
            add=0;
        }
    }
}null,tr[maxn];
treap::treap(int nv)
{
    v=nv;
    s=1;
    add=lazy=0;
    son[0]=son[1]=&null;
}
treap* NewNode(int x)
{
    tr[cnt]=treap(x);
    return tr+cnt++;
}
struct splaytree
{
    int Size;
    treap* root;
    splaytree(){ Size=0; root=&null; }
    void Rotate(treap* &t,int d)  //翻转操作
    {
        t->pushdown();
        treap* p=t->son[d^1];
        p->pushdown();
        t->son[d^1]=p->son[d];
        p->son[d]=t;
        t->pushup();
        t=p;
        t->pushup();
    }
    void Splay(treap* &t,int k)  //将第k大的节点伸展到根
    {
        t->pushdown();
        int d=t->cmp(k);
        if(d!=-1)
        {
            if(d) Splay(t->son[d],k- t->rk());
            else Splay(t->son[d],k);
            Rotate(t,d^1);
        }
    }
    void Build(treap* &t,int le,int ri)  //将N个数建成一棵树
    {
        if(le>ri) return;
        int mid=(le+ri)/2;
        t=NewNode(A[mid]);
        Build(t->son[0],le,mid-1);
        Build(t->son[1],mid+1,ri);
        t->pushup();
    }
    void Add(treap* &t,int k,int a)  //加值
    {
        Splay(t,k);
        t->v+=a;
        t->son[0]->add+=a;
    }
    void Reverse(treap* &t,int k)  //翻转
    {
        Splay(t,k);
        treap* p=t->son[1];
        t->son[1]=&null;
        t->pushup();
        t->lazy=1;
        t->pushdown();
        Splay(t,k);
        t->son[1]=p;
        t->pushup();
    }
    void Insert(treap* &t,int x)  //插入
    {
        Splay(t,1);
        treap* p=NewNode(x);
        p->son[1]=t->son[1];
        p->pushup();
        t->son[1]=p;
        t->pushup();
        Size++;
    }
    void Remove(treap* &t)  删除
    {
        Splay(t,1);
        treap* next=t->son[1];
        t=next;
        t->pushdown();
        Size--;
    }
    void Move(treap* &t,int x)  //移动
    {
        if(x==1)
        {
            Splay(t,Size);
            treap* p=t->son[0];
            t->son[0]=&null;
            p->pushdown();
            Splay(p,1);
            t->son[1]=p;
            t->pushup();
        }
        else
        {
            Splay(t,1);
            treap* p=t->son[1];
            t->son[1]=&null;
            p->pushdown();
            Splay(p,Size-1);
            t->son[0]=p;
            t->pushup();
        }
    }
};
int N,M,K1,K2;
int main()
{
    int Case=0;
    while(scanf("%d%d%d%d",&N,&M,&K1,&K2)!=EOF)
    {
        if(!N&&!M&&!K1&&!K2) break;
        for(int i=1;i<=N;i++) scanf("%d",&A[i]);
        cnt=0;
        splaytree spt;
        spt.Build(spt.root,1,N);
        spt.Size=N;
        printf("Case #%d:\n",++Case);
        while(M--)
        {
            char op[10];
            int x;
            scanf("%s",op);
            if(strcmp(op,"add")==0)
            {
                scanf("%d",&x);
                spt.Add(spt.root,K2,x);
            }
            else if(strcmp(op,"reverse")==0) spt.Reverse(spt.root,K1);
            else if(strcmp(op,"insert")==0)
            {
                scanf("%d",&x);
                spt.Insert(spt.root,x);
            }
            else if(strcmp(op,"delete")==0) spt.Remove(spt.root);
            else if(strcmp(op,"move")==0)
            {
                scanf("%d",&x);
                spt.Move(spt.root,x);
            }
            else
            {
                spt.Splay(spt.root,1);
                printf("%d\n",spt.root->v);
            }
        }
    }
    return 0;
}
View Code

 

posted @ 2016-07-08 10:20  wust_ouyangli  阅读(254)  评论(0编辑  收藏  举报