码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2016-08-10 00:48:43      阅读:170      评论:0      收藏:0      [点我收藏+]

标签:

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. At first, the host tells the participant a sequence of numbers, {A1A2, ... An}. Then the host performs a series of operations and queries on the sequence which consists:

  1. ADD x y D: Add D to each number in sub-sequence {Ax ... Ay}. For example, performing "ADD 2 4 1" on {1, 2, 3, 4, 5} results in {1, 3, 4, 5, 5}
  2. REVERSE x y: reverse the sub-sequence {Ax ... Ay}. For example, performing "REVERSE 2 4" on {1, 2, 3, 4, 5} results in {1, 4, 3, 2, 5}
  3. REVOLVE x y T: rotate sub-sequence {Ax ... AyT times. For example, performing "REVOLVE 2 4 2" on {1, 2, 3, 4, 5} results in {1, 3, 4, 2, 5}
  4. INSERT x P: insert P after Ax. For example, performing "INSERT 2 4" on {1, 2, 3, 4, 5} results in {1, 2, 4, 3, 4, 5}
  5. DELETE x: delete Ax. For example, performing "DELETE 2" on {1, 2, 3, 4, 5} results in {1, 3, 4, 5}
  6. MIN x y: query the participant what is the minimum number in sub-sequence {Ax ... Ay}. For example, the correct answer to "MIN 2 4" on {1, 2, 3, 4, 5} is 2

To make the show more interesting, the participant is granted a chance to turn to someone else that means when Jackson feels difficult in answering a query he may call you for help. You task is to watch the TV show and write a program giving the correct answer to each query in order to assist Jackson whenever he calls.

Input

The first line contains (≤ 100000).

The following n lines describe the sequence.

Then follows M (≤ 100000), the numbers of operations and queries.

The following M lines describe the operations and queries.

Output

For each "MIN" query, output the correct answer.

Sample Input

5
1 
2 
3 
4 
5
2
ADD 2 4 1
MIN 4 5

Sample Output

5
题意:给你一个序列以及许多操作,包括区间更新、翻转、循环右移,插入,删除,查询
分析:都是Splay的一些基本的操作,更新和翻转使用lazy标记的思想就行了,对于循环右移,首先找出左端点移动的位置k,然后就是将[k,r]区间移动到[l,k-1]的前面去,我们可以先定位出[k,r],再调整出
[l-1,l],将[k,r]接上去就行了。插入操作也是通过变换找到这个子树,再新加节点就是了。
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;

#define Key_value ch[ch[root][1]][0]
const int MAXN = 200000+100;
const int INF = 0X3F3F3F3F;
int fa[MAXN],ch[MAXN][2],key[MAXN],sz[MAXN],add[MAXN],rev[MAXN],mi[MAXN];
int root,tot1;
int s[MAXN],tot2;//内存池、内存池容量
int a[MAXN];
int n,m;

void NewNode(int &r,int pre,int k)
{
    if(tot2) r=s[tot2--];
    else r=++tot1;
    ch[r][0]=ch[r][1]=0;
    fa[r]=pre;
    sz[r]=1;
    add[r]=rev[r]=0;
    key[r]=mi[r]=k;
}
void Update_Rev(int r)
{
    if(r==0) return;
    swap(ch[r][0],ch[r][1]);
    rev[r]^=1;
}
void Update_Add(int r,int val)
{
    if(r==0) return;
    add[r]+=val;
    key[r]+=val;
    mi[r]+=val;
}
void Push_Up(int r)
{
    sz[r]=sz[ch[r][0]]+sz[ch[r][1]]+1;
    mi[r]=key[r];
    if(ch[r][0]) mi[r]=min(mi[r],mi[ch[r][0]]);
    if(ch[r][1]) mi[r]=min(mi[r],mi[ch[r][1]]);
}
void Push_Down(int r)
{
    if(rev[r])
    {
        Update_Rev(ch[r][0]);
        Update_Rev(ch[r][1]);
        rev[r]=0;
    }
    if(add[r])
    {
        Update_Add(ch[r][0],add[r]);
        Update_Add(ch[r][1],add[r]);
        add[r]=0;
    }
}
void Build(int &x,int l,int r,int pre)
{
    if(l>r) return;
    int mid=(l+r)/2;
    NewNode(x,pre,a[mid]);
    Build(ch[x][0],l,mid-1,x);
    Build(ch[x][1],mid+1,r,x);
    Push_Up(x);
}
void Init()
{
    root=tot1=tot2=0;
    ch[root][0]=ch[root][1]=sz[root]=add[root]=rev[root]=fa[root]=0;
    mi[root]=INF;
    NewNode(root,0,INF);
    NewNode(ch[root][1],root,INF);
    Build(Key_value,1,n,ch[root][1]);
    Push_Up(ch[root][1]);
    Push_Up(root);
}
void Rotate(int x,int d)
{
    int y=fa[x];
    Push_Down(y);
    Push_Down(x);
    ch[y][!d]=ch[x][d];
    fa[ch[x][d]]=y;
    if(fa[y]) ch[fa[y]][ch[fa[y]][1]==y]=x;
    fa[x]=fa[y];
    ch[x][d]=y;
    fa[y]=x;
    Push_Up(y);
}
//伸展操作,将r调整到goal下面
void Splay(int r,int goal)
{
    Push_Down(r);
    while(fa[r]!=goal)
    {
        if(fa[fa[r]]==goal)
        {
            //这题有反转操作,需要先push_down,在判断左右孩子
            Push_Down(fa[r]);
            Push_Down(r);
            Rotate(r,ch[fa[r]][0]==r);
        }
        else
        {
            //这题有反转操作,需要先push_down,在判断左右孩子
            Push_Down(fa[fa[r]]);
            Push_Down(fa[r]);
            Push_Down(r);
            int y=fa[r];
            int d=(ch[fa[y]][0]==y);
            //两个方向不同,则先左旋再右旋
            if(ch[y][d]==r)
            {
                Rotate(r,!d);
                Rotate(r,d);
            }
            //两个方向相同,相同方向连续两次
            else
            {
                Rotate(y,d);
                Rotate(r,d);
            }
        }
    }
    Push_Up(r);
    if(goal==0) root=r;
}
int Get_Kth(int r,int k)
{
    Push_Down(r);
    int t=sz[ch[r][0]]+1;
    if(t==k)return r;
    if(t>k)return Get_Kth(ch[r][0],k);
    else return Get_Kth(ch[r][1],k-t);
}
int Get_Min(int r)
{
    Push_Down(r);
    while(ch[r][0])
    {
        r=ch[r][0];
        Push_Down(r);
    }
    return r;
}
void Erase(int r)
{
    if(r)
    {
        s[++tot2]=r;
        Erase(ch[r][0]);
        Erase(ch[r][1]);
    }
}
int Get_Max(int r)
{
    Push_Down(r);
    while(ch[r][1])
    {
        r=ch[r][1];
        Push_Down(r);
    }
    return r;
}
void update_add(int l,int r,int val)
{
    Splay(Get_Kth(root,l),0);
    Splay(Get_Kth(root,r+2),root);
    Update_Add(Key_value,val);
    Push_Up(ch[root][1]);
    Push_Up(root);
}
void update_rev(int l,int r)
{
    Splay(Get_Kth(root,l),0);
    Splay(Get_Kth(root,r+2),root);
    Update_Rev(Key_value);
    Push_Up(ch[root][1]);
    Push_Up(root);
}
void update_reve(int l,int r,int T)
{
    int len=r-l+1;
    T=(T%len+len)%len;
    if(T==0) return;
    int k=r-T+1;
    Splay(Get_Kth(root,k),0);
    Splay(Get_Kth(root,r+2),root);
    int tmp=Key_value;
    Key_value=0;
    Push_Up(ch[root][1]);
    Push_Up(root);
    Splay(Get_Kth(root,l),0);
    Splay(Get_Kth(root,l+1),root);
    Key_value=tmp;
    fa[Key_value]=ch[root][1];
    Push_Up(ch[root][1]);
    Push_Up(root);
}
void update_int(int x,int P)
{
    Splay(Get_Kth(root,x+1),0);
    Splay(Get_Kth(root,x+2),root);
    NewNode(Key_value,ch[root][1],P);
    Push_Up(ch[root][1]);
    Push_Up(root);
}
void update_del(int x)
{
    Splay(Get_Kth(root,x),0);
    Splay(Get_Kth(root,x+2),root);
    Erase(Key_value);
    fa[Key_value]=0;
    Key_value=0;
    Push_Up(ch[root][1]);
    Push_Up(root);
}
int query_min(int l,int r)
{
    Splay(Get_Kth(root,l),0);
    Splay(Get_Kth(root,r+2),root);
    return mi[Key_value];
}

char str[20];
int x,y,D,P,T;

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    Init();
    scanf("%d",&m);
    while(m--)
    {
        scanf("%s",str);
        if(strcmp(str,"ADD")==0)
        {
            scanf("%d%d%d",&x,&y,&D);
            update_add(x,y,D);
        }
        else if(strcmp(str,"REVERSE")==0)
        {
            scanf("%d%d",&x,&y);
            update_rev(x,y);
        }
        else if(strcmp(str,"REVOLVE")==0)
        {
            scanf("%d%d%d",&x,&y,&T);
            update_reve(x,y,T);
        }
        else if(strcmp(str,"INSERT")==0)
        {
            scanf("%d%d",&x,&P);
            update_int(x,P);
        }
        else if(strcmp(str,"DELETE")==0)
        {
            scanf("%d",&x);
            update_del(x);
        }
        else
        {
            scanf("%d%d",&x,&y);
            printf("%d\n",query_min(x,y));
        }
    }
    return 0;
}

 

 

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

标签:

原文地址:http://www.cnblogs.com/wangdongkai/p/5755144.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!