现在的位置: 首页 > 综合 > 正文

Splay小结

2019年08月21日 ⁄ 综合 ⁄ 共 11922字 ⁄ 字号 评论关闭

Splay基本操作:

1.rotate() 旋转操作---包含三种情况

2.splay() 伸展-----一般是旋到根或根的父亲的下面

3.rotate_to() 先找到要伸展的结点,再splay;

4.push_up() 向上维护根的信息

5.push_down()向下下放延迟标记

6.Cut() 删除一个区间

7.insert()插入一个区间

8.Flip()翻转一个区间

9.pred()求结点的前驱

10.succ()求结点的后继

11.dfs()中序遍历---为了输出序列.

12.built()二分建树

13.New_Node()新建结点--如果多个函数要用到则写,否则不用!

poj3468--其它数据结构也可以实现!

//12344261		3468	Accepted	4468K	2907MS	C++	3222B	2013-12-01 11:37:06
#include <iostream>
#include<cstdio>
using namespace std;
#define MAX 100010
#define bint __int64
int N,Q,tot;
int A[MAX];
struct Node
{
    int size,vol,add;
    bint sum;
    Node*d[2];
    Node*pre;
}*Null,*root,space[MAX];
void updata(Node*p)
{
    p->size=p->d[0]->size+p->d[1]->size+1;
    p->sum=p->d[0]->sum+p->d[1]->sum+p->vol;
}
void Push_down(Node*x)
{
    if(x==Null) return;
    x->vol+=x->add;
    x->d[0]->add+=x->add;
    x->d[1]->add+=x->add;
    if(x->d[0]!=Null)
        x->d[0]->sum+=(bint)(x->add)*(x->d[0]->size);
    if(x->d[1]!=Null)
        x->d[1]->sum+=(bint)(x->add)*(x->d[1]->size);
    x->add=0;
}
void Rotate(Node*x,int c)
{
    Node*y=x->pre;
    Push_down(y),Push_down(x);
    y->d[!c]=x->d[c],x->pre=y->pre;
    if(x->d[c]!=Null) x->d[c]->pre=y;
    if(y->pre!=Null) y->pre->d[y->pre->d[1]==y]=x;
    y->pre=x,x->d[c]=y;
    if(root==y) root=x;
    updata(y);
}
void Splay(Node*x,Node*f)
{
    for(Push_down(x);x->pre!=f;)
    {
        if(x->pre->pre==f)
            Rotate(x,x->pre->d[0]==x);
        else
        {
            Node *y=x->pre , *z=y->pre;
            if(z->d[0]==y)
                if(y->d[0]==x)
                    Rotate(y,1),Rotate(x,1);
                else
                    Rotate(x,0),Rotate(x,1);
            else
                if(y->d[1]==x)
                    Rotate(y,0),Rotate(x,0);
                else
                    Rotate(x,1),Rotate(x,0);
        }
    }
    updata(x);
}
Node* New_Node(int x)
{
    Node*p=&space[tot++];
    p->d[0]=p->d[1]=p->pre=Null;
    p->add=0;
    p->size=1;
    p->sum=p->vol=x;
    return p;
}
Node* Make_Tree(int l,int r,Node* fa)
{
    if(l>r) return Null;
    int m=(l+r)>>1;
    Node*p=New_Node(A[m]);
    p->d[0]=Make_Tree(l,m-1,p);
    p->d[1]=Make_Tree(m+1,r,p);
    p->pre=fa;
    updata(p);
    return p;
}
void init()
{
    tot=0;
    Null=New_Node(0);
    Null->size=0;
    root=New_Node(-1);
    root->d[1]=New_Node(-1);
    root->d[1]->pre=root;
    updata(root);
    root->d[1]->d[0]=Make_Tree(1,N,root->d[1]);
}
void Select(int k,Node*f)
{
    Node*p=root;
    while(true)
    {
        Push_down(p);
        int tem=p->d[0]->size;
        if(k==tem+1) break;
        if(k <= tem)
            p=p->d[0];
        else
            p=p->d[1],k-=tem+1;
    }
    Splay(p,f);
}
int main()
{
    while(~scanf("%d%d",&N,&Q))
    {
        for(int i=1;i<=N;i++)
            scanf("%d",&A[i]);
        init();
        char op[2];
        for(int i=1;i<=Q;i++)
        {
            scanf("%s",op);
            if(op[0]=='C')
            {
                int a,b,c;
                scanf("%d%d%d",&a,&b,&c);
                Select(a,Null);
                Select(b+2,root);
                root->d[1]->d[0]->add+=c;
                root->d[1]->d[0]->sum+=(bint)c*(root->d[1]->d[0]->size);
            }
            else
            {
                int a,b;
                scanf("%d%d",&a,&b);
                Select(a,Null);
                Select(b+2,root);
                printf("%I64d\n",root->d[1]->d[0]->sum);
            }
        }
    }
    return 0;
}

hdu4441---指定位置插入(最好用splay)

//9740664	2013-12-02 22:21:47	Accepted	4441	1140MS	9464K	3860 B	G++	
#include<cstdio>
#include<queue>
#include<vector>
#include<cstring>
#include<iostream>
using namespace std;
#define Stype(x) (ns[ns[x].f].son[1]==x)
typedef __int64 ll;
const int N = 100005;
int m;int posn[N],posp[N];
struct Splay
{
    int nns,begin,end;
    struct node{int size,key,f,son[2]; ll sum; bool p;}ns[2*N];
    inline int operator[](int x){return ns[x].key;}
    inline int NewNode(int x,int f)
    {
        ns[++nns].key=ns[nns].sum=x;
        ns[nns].size=1;
        ns[nns].f=f;
        ns[nns].p=x>0;
        return nns;
    }
    inline void init()
    {
        nns=0;
        memset(ns,0,sizeof(ns));
        begin=ns[0].son[0]=NewNode(0,0);
        end=ns[1].son[1]=NewNode(0,1);
        Updata(1);
    }
    inline void Updata(int x)
    {
        ns[x].sum=ns[ns[x].son[0]].sum+ns[ns[x].son[1]].sum+ns[x].key;
        ns[x].size=ns[ns[x].son[0]].size+ns[ns[x].son[1]].size+1;
        ns[x].p=ns[x].key>0 || ns[ns[x].son[0]].p || ns[ns[x].son[1]].p;
    }
    int pred(int x)
    {
        splay(x);
        for(x=ns[x].son[0];ns[x].son[1];x=ns[x].son[1]);
        splay(x);return x;
    }
    int succ(int x)
    {
        splay(x);
        for(x=ns[x].son[1];ns[x].son[0];x=ns[x].son[0]);
        splay(x);return x;
    }
    int ins(int x,int s)
    {
        //cout<<"asdasda\n";
        int p=pred(s);
        splay(p),splay(s,p);
        x=ns[s].son[0]=NewNode(x,s);
        Updata(s),Updata(p);
        splay(x);return x;
    }
    int kth(int k)
    {
        int x=ns[0].son[0],ls;
        while(true)
        {
            ls=ns[ns[x].son[0]].size;
            if(ls+1==k) {splay(x);return x;}
            if(ls < k)
                x=ns[x].son[1],k-=ls+1;
            else
                x=ns[x].son[0];
        }
    }
    int F(int x)
    {
        splay(x);x=ns[x].son[1];
        if(!ns[x].p) return 0;
        while(true)
        {
            if(ns[ns[x].son[0]].p)  x=ns[x].son[0];
            else if(ns[x].key > 0) {splay(x);return x;}
            else                    x=ns[x].son[1];
        }
    }
    void rot(int x)
    {
        int ST=Stype(x),f=ns[x].f;
        ns[ns[f].f].son[Stype(f)]=x;
        ns[x].f=ns[f].f;
        ns[f].son[ST]=ns[x].son[!ST];
        if(ns[x].son[!ST]) ns[ns[x].son[!ST]].f=f;
        ns[f].f=x;
        ns[x].son[!ST]=f;
        Updata(f);
    }
    void splay(int x,int to=0)
    {
        while(ns[x].f!=to)
            if(ns[ns[x].f].f!=to)
            {
                if(Stype(x)==Stype(ns[x].f))
                    rot(ns[x].f),rot(x);
                else
                    rot(x),rot(x);
            }
            else rot(x);
        Updata(x);
    }
    void Del(int x)
    {
        int s=succ(x),p=pred(x);
        splay(p),splay(s,p);
        ns[s].son[0]=0;
        Updata(s),Updata(p);
    }
    ll S(int l,int r)
    {
        splay(l),splay(r,l);
        return ns[ns[r].son[0]].sum;
    }
}T;
void run()
{
    priority_queue< int, vector<int>, greater<int> > H;
    for(int i=1;i<=m;i++) H.push(i);
    T.init();
    char ch[8];int x,w,w2,key;
    for(int i=1;i<=m;i++)
    {
        scanf("%s%d",ch,&x);
        if(ch[0]=='i')
        {
            key=H.top();H.pop();
            posp[key]=w=T.ins(key,T.kth(x+2));
            w2=T.F(w);
            if(w2)
            posn[key]=T.ins(-key,posn[T[w2]]);
            else
            posn[key]=T.ins(-key,T.end);
        }
        else if(ch[0]=='r')
        {
            T.Del(posn[x]); T.Del(posp[x]);
            H.push(x);
        }
        else
            printf("%I64d\n", T.S(posp[x], posn[x]));
    }
}
int main()
{
    int t=0;
    while(~scanf("%d",&m))
    {
        printf("Case #%d:\n", ++t);
        run();
    }
    return 0;
}

hdu3487--区间翻转,切割

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN = 333333;
#define m_set(ptr,v,type,size) memset(ptr,v,sizeof(type)*size)
#define loop(begin,end) for(int i=begin;i<end;i++)
class SplayTree{
    #define l(x) (nod[x].son[0])
    #define r(x) (nod[x].son[1])
    #define Juge(x) (nod[pre[x]].son[1]==x)
    #define mid(x,y) ((x+y)>>1)
public:
    int a[MAXN],pre[MAXN];
    struct node{int val,rev,sz,son[2];}nod[MAXN];
    int root,tot;
    void init(){
        memset(nod,0,sizeof(nod));
        root = tot = 0;
    }
    void read(int n){
        a[1] = a[n+2] = 0;
        loop(2,n+2){ a[i] = i-1; }
    }
    void push_up(int rt){
        nod[rt].sz=nod[l(rt)].sz+nod[r(rt)].sz+1;
    }
    void swap(int &x,int &y){
        int tmp = x;
        x = y;
        y = tmp;
    }
    void push_down(int rt){
        if(nod[rt].rev){
            swap(l(rt),r(rt));
            if(l(rt)) nod[l(rt)].rev ^= 1;//采用异或 ^=
            if(r(rt)) nod[r(rt)].rev ^= 1;
            nod[rt].rev = 0;
        }
    }
    void rotate(int x,int f){
        /**分三步旋转**/
        /**第一步:把x和y的儿子连好**/
        int y = pre[x];
        nod[y].son[!f]=nod[x].son[f];
        if(nod[y].son[!f]) pre[nod[y].son[!f]] = y;
        push_up(y);
        /**第二步:把x的父亲连好**/
        if(pre[y]) nod[pre[y]].son[r(pre[y])==y]=x;
        pre[x] = pre[y];
        /**第三步:把y的父亲连好**/
        nod[x].son[f] = y;
        pre[y] = x;
    }
    void splay(int x,int goal)
    {
        /**分三种情形的旋转!**/
        while(pre[x]!=goal)
        {
            int y = pre[x], z = pre[pre[x]];
            if(z==goal)
            {
                rotate(x,!Juge(x));
            }
            else
            {
                if(Juge(y))
                {
                    if(Juge(x)) rotate(y,0),rotate(x,0);
                    else        rotate(x,1),rotate(x,0);
                }
                else
                {
                    if(!Juge(x)) rotate(y,1),rotate(x,1);
                    else         rotate(x,0),rotate(x,1);
                }
            }
        }
        push_up(x);/**最后在更新x的信息,没必要在rotate里面去更新,它里面只需更新改动的父亲结点信息!**/
        if(goal==0) root = x;/**要记得维护一下 root的信息!**/
    }
    void rotateTo(int k,int goal){
        /**先找到第k个位置,然后splay到goal!**/
        int x = root;
        while(1){
            push_down(x);
            int tmp = nod[l(x)].sz+1;
            if(k==tmp) break;
            else if(k<tmp) x = l(x);
            else{
                k -= tmp;
                x = r(x);
            }
        }
        splay(x,goal);
    }
    void buildTree(int l,int r,int &rt,int f){
        /**二分的去建树!**/
        if(l>r)return;
        int m = mid(l,r);
        rt = ++tot;
        nod[rt].val=a[m];
        pre[rt] = f;
        buildTree(l,m-1,l(rt),rt);
        buildTree(m+1,r,r(rt),rt);
        push_up(rt);/**返回的时候,将根结点信息更新!**/
    }
    void rangeCut(int l,int r,int goal){
        /**先删除一段**/
        rotateTo(l-1,0);
        rotateTo(r+1,root);
        int x = l(r(root));
        l(r(root)) = 0;
        pre[x] = 0;
        push_up(r(root));
        push_up(root);
        /**后插入一段**/
        rotateTo(goal,0);
        rotateTo(goal+1,root);
        l(r(root)) = x;
        pre[x] = r(root);
        push_up(r(root));
        push_up(root);
    }
    void rangeFlip(int l,int r){
        rotateTo(l-1,0);
        rotateTo(r+1,root);
        int x = l(r(root));
        nod[x].rev^=1;/**延迟标记**/
    }
    void dfs(int rt,int &size){
        if(!rt) return;
        push_down(rt);/**遍历使要下放延迟标记,才能得到正确结果!**/
        dfs(l(rt),size);
        a[size++] = nod[rt].val;
        dfs(r(rt),size);
    }
    /////////////////debug///////////////////////

}spt;
int main(){
    int n,m;
    while(scanf("%d%d",&n,&m),!(n<0&&m<0)){
        spt.init();
        spt.read(n);
        spt.buildTree(1,n+2,spt.root,0);
        char op[5]; int a,b,c;
        while(m--){
            scanf("%s%d%d",op,&a,&b);
            if(op[0]=='C'){
                scanf("%d",&c);
                spt.rangeCut(a+1,b+1,c+1);
            }else{
                spt.rangeFlip(a+1,b+1);
            }
        }
        n = 0;
        spt.dfs(spt.root,n);
        loop(1,n-1){
            if(i!=1)printf(" ");
            printf("%d",spt.a[i]);
        }
        printf("\n");
    }
    return 0;
}

hdu4286--双向链表实现的区间翻转\

TLE  普通的翻转,即每翻转一次就把区间里所有节点都翻转过来!

#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 500010
struct Node
{
    int pred,last,vol;
}a[maxn];
int l,r,tot,size;
void reverse()
{
    for(int i=a[l].last;i!=r;i=a[i].pred) swap(a[i].pred,a[i].last);
    a[a[l].last].last=r;
    a[a[r].pred].pred=l;
    swap(a[l].last,a[r].pred);
}
void Del(char ch)
{
    size--;
    if(ch=='L')
    {
        a[a[a[l].last].last].pred=l;
        a[l].last=a[a[l].last].last;
    }
    else
    {
        a[a[a[r].pred].pred].last=r;
        a[r].pred=a[a[r].pred].pred;
    }
}
void init(int n)
{
    tot=0;size=0;
    l=0;r=n+1;
    a[l].pred=-1;a[l].last=r;
    a[r].pred=l;a[r].last=-1;
}
void Insert(char ch,int vol)
{
    a[++tot].vol=vol;size++;
    if(ch=='L')
    {
        a[tot].pred=l;
        a[tot].last=a[l].last;
        a[a[l].last].pred=tot;
        a[l].last=tot;
    }
    else
    {
        a[tot].last=r;
        a[tot].pred=a[r].pred;
        a[a[r].pred].last=tot;
        a[r].pred=tot;
    }
}
void left(char ch)
{
    if(ch=='L') l=a[l].pred;
    else        r=a[r].pred;
}
void right(char ch)
{
    if(ch=='L') l=a[l].last;
    else        r=a[r].last;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {

        int n;
        scanf("%d",&n);
        init(n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[++tot].vol);
            a[tot].pred=l;
            a[tot].last=a[l].last;
            a[l].last=tot;
            a[a[tot].last].pred=tot;
            l=tot;size++;
        }
        scanf("%d%d",&l,&r);l--;r++;
        int m;
        scanf("%d",&m);
        while(m--)
        {
            char op[10];
            scanf("%s",op);
            if(op[0]=='R') {reverse(); continue;}
            else if(op[0]=='D') {scanf(" %c",&op[0]);Del(op[0]);}
            else if(op[0]=='I') {int d;scanf(" %c%d",&op[0],&d);Insert(op[0],d);}
            else
            {
                char ch;
                scanf(" %c",&ch);
                if(strcmp(op,"MoveLeft")==0)  left(ch);
                else                        right(ch);
            }
        }

        for(int i=1,k=0;i<=size;i++)
        {
            k=a[k].last;
            if(i==1)    printf("%d",a[k].vol);
            else        printf(" %d",a[k].vol);
        }
        printf("\n");
    }
    return 0;
}

只要 在L 的前面设一个 LL 在R后面设一个 RR就可以避免上述的没翻转一次全部结点翻转了!

这样的话,LL就相当于是给 L 一个方向感! RR也是一样的,只不过它代表R的后.

/*
HDU
G++  4015ms  11968K
双向链表模拟
注意细节
*/

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<algorithm>
using namespace std;
const int MAXN=2000000;
struct Node
{
    int from;
    int to;
    int val;
}node[MAXN];
int tol;

int L,R;//两个指针
int LL,RR;//分别是指针L,R的左侧和右侧,由于倒一下可能改变方向,所以记录下方向
int n;

void moveleft_L(void)//左移L指针
{
    if(L==0)return;//最左侧了
    if(node[L].to==LL)
    {
        LL=L;
        L=node[L].from;
    }
    else
    {
        LL=L;
        L=node[L].to;
    }
}

void moveleft_R()
{
    if(RR==0)return;
    if(node[RR].to==R)
    {
        R=RR;
        RR=node[RR].from;
    }
    else
    {
        R=RR;
        RR=node[RR].to;
    }
}
void moveright_L()
{
    if(LL==n+1)return;
    if(L==node[LL].from)
    {
        L=LL;
        LL=node[LL].to;
    }
    else
    {
        L=LL;
        LL=node[LL].from;
    }
}

void moveright_R()
{
    if(R==n+1)return;
    if(node[R].from==RR)
    {
        RR=R;
        R=node[R].to;
    }
    else
    {
        RR=R;
        R=node[R].from;
    }
}

void insert_L(int v)
{
    node[tol].val=v;
    node[tol].from=L;
    node[tol].to=LL;
    if(node[L].to==LL)node[L].to=tol;
    else node[L].from=tol;
    if(node[LL].from==L)node[LL].from=tol;
    else node[LL].to=tol;
    LL=tol;
    tol++;
}
void insert_R(int v)
{
    node[tol].val=v;
    node[tol].from=RR;
    node[tol].to=R;
    if(node[RR].to==R)node[RR].to=tol;
    else node[RR].from=tol;
    if(node[R].from==RR)node[R].from=tol;
    else node[R].to=tol;
    RR=tol;
    tol++;
}

void del_L()
{
    if(LL==n+1)return;
    if(L==n+1)return;
    int t;
    if(node[LL].from==L)t=node[LL].to;
    else t=node[LL].from;

    if(node[t].from==LL)node[t].from=L;
    else node[t].to=L;

    if(node[L].to==LL)node[L].to=t;
    else node[L].from=t;

    LL=t;
}

void del_R()
{
    if(RR==0)return;
    if(R==0)return;
    int t;
    if(node[RR].to==R)t=node[RR].from;
    else t=node[RR].to;

    if(node[t].from==RR)node[t].from=R;
    else node[t].to=R;

    if(node[R].from==RR)node[R].from=t;
    else node[R].to=t;

    RR=t;
}

void reverse()
{
    if(node[L].to==LL)node[L].to=RR;
    else node[L].from=RR;

    if(node[LL].from==L)node[LL].from=R;
    else node[LL].to=R;

    if(node[R].from==RR)node[R].from=LL;
    else node[R].to=LL;

    if(node[RR].to==R)node[RR].to=L;
    else node[RR].from=L;

    int temp;
    temp=LL;
    LL=RR;
    RR=temp;
}

void output()
{
    int flag=true;
    int tt=0;
    for(int i=node[0].to;i!=n+1;)
    {
        if(flag)flag=false;
        else printf(" ");

        printf("%d",node[i].val);

        if(node[i].from==tt)
        {
            tt=i;
            i=node[i].to;
        }
        else
        {
            tt=i;
            i=node[i].from;
        }
    }
    printf("\n");
}

char str[20];
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int T;
    int m;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&node[i].val);
            node[i].from=i-1;
            node[i].to=i+1;
        }
        node[0].to=1;
        node[0].from=-1;
        node[n+1].from=n;
        node[n+1].to=-1;
        tol=n+2;//结点数
        scanf("%d%d",&LL,&RR);
        L=LL-1;
        R=RR+1;
        scanf("%d",&m);
        while(m--)
        {
            scanf("%s",&str);
            if(strcmp(str,"MoveLeft")==0)
            {
                scanf("%s",&str);
                if(str[0]=='L')moveleft_L();
                else moveleft_R();
            }
            else if(strcmp(str,"MoveRight")==0)
            {
                scanf("%s",&str);
                if(str[0]=='L')moveright_L();
                else moveright_R();
            }
            else if(strcmp(str,"Delete")==0)
            {
                scanf("%s",&str);
                if(str[0]=='L')del_L();
                else del_R();
            }
            else if(strcmp(str,"Insert")==0)
            {
                scanf("%s",&str);
                if(str[0]=='L')
                {
                    int v;
                    scanf("%d",&v);
                    insert_L(v);
                }
                else
                {
                    int v;
                    scanf("%d",&v);
                    insert_R(v);
                }
            }
            else reverse();
        }
        output();
    }
}

【上篇】
【下篇】

抱歉!评论已关闭.