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\n",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;
}

原文地址:https://www.cnblogs.com/HooYing/p/12014227.html

时间: 2024-09-29 17:57:03

poj 3580 SuperMemo (splay模板)的相关文章

poj 3580 SuperMemo splay树模板题

题意: 给一个序列,对其进行各种操作.在对序列仅对操作的处理上,splay是比线段树强大的,虽然均摊复杂度均为logN,但它能支持1:在某个位置插入一些连续的数,2:在某个位置删除一些连续的数.只是splay随便一些200+行. 分析: 网上各种模板介绍漫天飞,这个还算简洁明了. 代码: //poj 3580 #include <stdio.h> #define maxN 200000 int N,T,node; int a[maxN],size[maxN],left[maxN],right[

poj 3580 SuperMemo (Splay)

poj 3580 好恶心的题目,真是各种操作都来了个遍 ... 不过Splay树真是一种神奇的东西,通过旋转就能实现各种操作,而且方法也都相差不大 . 题意: 给出一个数字序列,有6种操作: (1) ADD x y d: 第x个数到第y个数加d . (2) REVERSE x y : 将区间[x,y]中的数翻转 . (3) REVOLVE x y t :将区间[x,y]旋转t次,如1 2 3 4 5 旋转2次后就变成4 5 1 2 3 . (4) INSERT x p :在第x个数后面插入p .

POJ 3580 SuperMemo (Splay 区间更新、翻转、循环右移,插入,删除,查询)

SuperMemo Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 13917   Accepted: 4352 Case Time Limit: 2000MS Description Your friend, Jackson is invited to a TV show called SuperMemo in which the participant is told to play a memorizing game

POJ 3580 SuperMemo

裸Splay区间操作: 内存池+区间加减+区间翻转+插入+删除+维护最值 SuperMemo Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 8552   Accepted: 2801 Case Time Limit: 2000MS Description Your friend, Jackson is invited to a TV show called SuperMemo in which the participa

POJ 3580 - SuperMemo - [伸展树splay]

题目链接:http://poj.org/problem?id=3580 Your friend, Jackson is invited to a TV show called SuperMemo in which the participant is told to play a memorizing game. At first, the host tells the participant a sequence of numbers, {A1, A2, ... An}. Then the h

Splay树(多操作)——POJ 3580 SuperMemo

对应POJ题目:点击打开链接 SuperMemo Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 11309   Accepted: 3545 Case Time Limit: 2000MS Description Your friend, Jackson is invited to a TV show called SuperMemo in which the participant is told to play a

又一道Splay吐血题 [POJ 3580] SuperMemo

SuperMemo Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 9878   Accepted: 3177 Case Time Limit: 2000MS Description Your friend, Jackson is invited to a TV show called SuperMemo in which the participant is told to play a memorizing game.

平衡树:Splaytree POJ 3580 SuperMemo

SuperMemo Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 12788   Accepted: 3986 Case Time Limit: 2000MS Description Your friend, Jackson is invited to a TV show called SuperMemo in which the participant is told to play a memorizing game

POJ 3580 SuperMemo 题解

题目大意:维护一个序列,支持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 插入P到第x个数后面 5.DELETE x 删除第x个数 6.MIN x y 查询第x个数到第y个数之间最小值 ADD和REVERSE打标记然后及时下传就可以..REVOLVE的T可能为负还可能很大,要注意取模.REVOLVE可以通过3个REVERSE操作完成,也可以