• poj 3580 SuperMemo (splay模板)


    题意

    给出一个数字序列,有6种操作:
    (1)ADD x y d: 第x个数到第y个数加d 。
    (2)REVERSE x y : 将区间[x,y]中的数翻转 。
    (3)REVOLVE x y t :将区间[x,y]旋转t次。
    (4)INSERT x p :在第x个数后面插入p 。
    (5)DELETE x :删除第x个数 。
    (6)MIN x y : 查询区间[x,y]中的最小值 。

    思路

    splay板子题,对于区间[l,r],将l-1旋为树根,将r+1旋为根的右孩子,那么r+1的左子树就是区间[l,r]。
    区间旋转就是把区间分成两段,然后交换一下,因此我们可以把后一段区间处理到一个子树上,保存然后删除,接着再处理到前一段区间的前面。

    #include<cstdio>
    #include<iostream>
    using namespace std;
    const int maxx = 2e5+10;
    const int inf = 0x3f3f3f3f;
    int ch[maxx][2],fa[maxx],siz[maxx],key[maxx];
    int rev[maxx],lazy[maxx],w[maxx],mi[maxx];
    int rt,sz;
    char s[20];
    int get(int x)
    {
        return ch[fa[x]][1]==x;
    }
    void update(int x)
    {
        if(!x)return;
        siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
        mi[x]=key[x];
        if(ch[x][0])mi[x]=min(mi[x],mi[ch[x][0]]);
        if(ch[x][1])mi[x]=min(mi[x],mi[ch[x][1]]);
    }
    void pushdown(int x)
    {
        if(!x)return;
        if(rev[x])
        {
            rev[ch[x][0]]^=1;
            rev[ch[x][1]]^=1;
            swap(ch[x][0],ch[x][1]);
            rev[x]=0;
        }
        if(lazy[x])
        {
            lazy[ch[x][0]]+=lazy[x];
            lazy[ch[x][1]]+=lazy[x];
            key[ch[x][0]]+=lazy[x];
            key[ch[x][1]]+=lazy[x];
            mi[ch[x][0]]+=lazy[x];
            mi[ch[x][1]]+=lazy[x];
            lazy[x]=0;
        }
    }
    void rotate(int x)
    {
        int y=fa[x],z=fa[y],k=get(x);
        pushdown(x);pushdown(y);
        ch[y][k]=ch[x][k^1];fa[ch[y][k]]=y;
        ch[x][k^1]=y;fa[y]=x;fa[x]=z;
        if(z)ch[z][ch[z][1]==y]=x;
        update(y);update(x);
    }
    void splay(int x,int goal) 
    {
        for(int y;(y=fa[x])!=goal;rotate(x))
            if(fa[y]!=goal)rotate((get(x)==get(y))?y:x);
        if(goal==0)rt=x; //注意
    }
    int findkth(int k) //找第k个节点
    {
        int x=rt;
        while(1)
        {
            pushdown(x);
            if(k<=siz[ch[x][0]])x=ch[x][0];
            else
            {
                k-=siz[ch[x][0]]+1;
                if(!k)return x;
                x=ch[x][1];
            }
        }
    }
    int build(int l,int r,int f)
    {
        if(l>r)return 0;
        int mid=(l+r)/2;
        int x=++sz;
        fa[x]=f;
        key[x]=w[mid];
        ch[x][0]=build(l,mid-1,x);
        ch[x][1]=build(mid+1,r,x);
        update(x);
        return x;
    }
    void add(int l,int r,int val) //区间加
    {
        int x=findkth(l-1),y=findkth(r+1);
        splay(x,0);splay(y,x);
        int tmp=ch[ch[rt][1]][0];
        key[tmp]+=val;
        mi[tmp]+=val;
        lazy[tmp]+=val;
        update(ch[rt][1]);
        update(rt);     
    }
    void Insert(int k,int val) //在第k个数后插入值为x的节点
    {
        int x=findkth(k),y=findkth(k+1);
        splay(x,0);splay(y,x);
        ch[ch[rt][1]][0]=++sz;
        fa[sz]=ch[rt][1];
        key[sz]=mi[sz]=val;
        siz[sz]=1;
        update(ch[rt][1]);
        update(rt);
    }
    void Delete(int k) //删除第k个节点
    {
        int x=findkth(k-1),y=findkth(k+1);
        splay(x,0);splay(y,x);
        ch[ch[rt][1]][0]=0;
        update(ch[rt][1]);
        update(rt);
    }
    void Reverse(int l,int r) //区间翻转
    {
        int x=findkth(l-1),y=findkth(r+1);
        splay(x,0); //x旋转为根
        splay(y,x); //y旋转为根的右孩子
        //旋转完之后y的左子树为区间[l,r]
        rev[ch[ch[rt][1]][0]]^=1; //lazy标记是否要旋转其左右子树
    }
    void revolve(int l1,int r1,int l2,int r2) //区间旋转
    {
        int x=findkth(l2-1),y=findkth(r2+1);
        splay(x,0);splay(y,x);
        int tmp=ch[ch[rt][1]][0];ch[ch[rt][1]][0]=0; 
        update(ch[rt][1]);update(rt);
        x=findkth(l1-1);y=findkth(l1);
        splay(x,0);splay(y,x);
        ch[ch[rt][1]][0]=tmp;
        fa[tmp]=ch[rt][1];
        update(ch[rt][1]);update(rt);
    }
    int getmi(int l,int r) //找区间最小值
    {
        int x=findkth(l-1),y=findkth(r+1);
        splay(x,0);splay(y,x);
        return mi[ch[ch[rt][1]][0]];
    }
    int main()
    {
        int n,m;
        scanf("%d",&n);
        w[1]=-inf;w[n+2]=inf;
        for(int i=2;i<=n+1;i++)scanf("%d",&w[i]);
        rt=build(1,n+2,0);
        scanf("%d",&m);
        int x,y,z;
        while(m--)
        {
            scanf("%s",s);
            if(s[0]=='A')scanf("%d%d%d",&x,&y,&z),add(x+1,y+1,z);
            else if(s[0]=='I')scanf("%d%d",&x,&y),Insert(x+1,y);
            else if(s[0]=='D')scanf("%d",&x),Delete(x+1);
            else if(s[0]=='M')scanf("%d%d",&x,&y),printf("%d
    ",getmi(x+1,y+1));
            else if(s[3]=='E')scanf("%d%d",&x,&y),Reverse(x+1,y+1);
            else
            {
                scanf("%d%d%d",&x,&y,&z);
                z=z%(y-x+1);
                if(z)revolve(x+1,y-z+1,y-z+2,y+1);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    [转] packagelock.json
    前端框架和技术
    typescript
    微信小程序登陆流程
    Introduction to my galaxy engine 4: Test on local light model
    Introduction to my galaxy engine 3: Local light model
    Introduction to my galaxy engine 5: Differed Lighting
    Introduction to my galaxy engine 2: Depth of field
    自己整理的一些国外免费3D模型网站,以后还会陆续添加
    Introduction to my galaxy engine 6: Differed Lighting 2
  • 原文地址:https://www.cnblogs.com/HooYing/p/12014227.html
Copyright © 2020-2023  润新知