Splay(hdu4441Queue Sequence)好题

Queue Sequence

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1412    Accepted Submission(s): 356


Problem Description
There's a queue obeying the first in first out rule. Each time you can either push a number into the queue (+i), or pop a number out from the queue (-i). After a series of operation, you get a sequence (e.g. +1 -1 +2 +4 -2 -4). We call this sequence a queue sequence.

Now you are given a queue sequence and asked to perform several operations:

1. insert p
First you should find the smallest positive number (e.g. i) that does not appear in the current queue sequence, then you are asked to insert the +i at position p (position starts from 0). For -i, insert it into the right most position that result in a valid queue sequence (i.e. when encountered with element -x, the front of the queue should be exactly x).
For example, (+1 -1 +3 +4 -3 -4) would become (+1 +2 -1 +3 +4 -2 -3 -4) after operation 'insert 1'.
2. remove i
Remove +i and -i from the sequence.
For example, (+1 +2 -1 +3 +4 -2 -3 -4) would become (+1 +2 -1 +4 -2 -4) after operation 'remove 3'.
3. query i
Output the sum of elements between +i and -i. For example, the result of query 1, query 2, query 4 in sequence (+1 +2 -1 +4 -2 -4) is 2, 3(obtained by -1 + 4), -2 correspond.
 

Input
There are less than 25 test cases. Each case begins with a number indicating the number of operations n (1 ≤ n ≤ 100000). The following n lines with be 'insert p', 'remove i' or 'query i'(0 ≤ p ≤ length (current sequence), 1 ≤ i, i is granted to be in the sequence).
In each case, the sequence is empty initially.
The input is terminated by EOF.
 

Output
Before each case, print a line "Case #d:" indicating the id of the test case.
After each operation, output the sum of elements between +i and -i.
 

Sample Input
  
  
10 insert 0 insert 1 query 1 query 2 insert 2 query 2 remove 1 remove 2 insert 2 query 3 6 insert 0 insert 0 remove 2 query 1 insert 1 query 2
 

Sample Output
  
  
Case #1: 2 -1 2 0 Case #2: 0 -1
 

Source


题目支持三种操作:

insert pos, 把x(x为可用的最小的数)插入对应位置,-x插入对应位置,如1 2 -1 -2 ,3要插入2后面,-3插入-2后面,而求尽量靠右

remove x,把x,-x移除

query x询问x与-x之间的数的和

position数组保存x对应的伸展树中的编号,线段树维护最小的可用的数

insert操作插入x的时候比较好操作,-x的时候,因为要保持顺序,所以x前面有多少个正数,-x前面就有多少个负数,又因为尽力量靠右,所以也就是第n+1个负数的左边

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
#define Key_value ch[ch[root][1]][0]
const int maxn=200010;
const int INF=1000000000;
typedef long long LL;
int M;
int ch[maxn][2],size[maxn],pre[maxn],cnt[maxn][2],key[maxn];
LL sum[maxn];
int position[maxn][2];
int root,tot1,tot2;
set<int> sp;
void NewNode(int &r,int f,int val)
{
    r=++tot1;
    ch[r][0]=ch[r][1]=0;
    cnt[r][0]=val>0;
    cnt[r][1]=val<0;
    sum[r]=val;
    pre[r]=f;
    size[r]=1;
    key[r]=val;
}
void pushup(int r)
{
    if(!r)return;
    int lson=ch[r][0],rson=ch[r][1];
    size[r]=size[lson]+size[rson]+1;
    sum[r]=sum[lson]+sum[rson]+key[r];
    cnt[r][0]=cnt[lson][0]+cnt[rson][0]+(key[r]>0);
    cnt[r][1]=cnt[lson][1]+cnt[rson][1]+(key[r]<0);
}
void init()
{
    root=tot1=tot2=0;
    ch[root][0]=ch[root][1]=pre[root]=cnt[root][0]=cnt[root][1]=key[root]=size[root]=0;
    NewNode(root,0,0);
    NewNode(ch[root][1],root,0);
    pushup(ch[root][1]);
    pushup(root);
   // cout<<size[root]<<"***"<<endl;
}
void Rotate(int x,int kind)
{

    int y=pre[x];
    ch[y][!kind]=ch[x][kind];
    pre[ch[x][kind]]=y;
    if(pre[y])ch[pre[y]][ch[pre[y]][1]==y]=x;
    pre[x]=pre[y];
    ch[x][kind]=y;
    pre[y]=x;
    pushup(y);
}
void Splay(int r,int goal)
{
    while(pre[r]!=goal)
    {
        if(pre[pre[r]]==goal)
        {
            Rotate(r,ch[pre[r]][0]==r);
        }
        else
        {
            int y=pre[r];
            int kind=(ch[pre[y]][0]==y);
            if(ch[y][kind]==r)
            {
                Rotate(r,!kind);
                Rotate(r,kind);
            }
            else
            {
                Rotate(y,kind);
                Rotate(r,kind);
            }
        }
    }
    pushup(r);
    if(goal==0)root=r;
}
int get_kth(int r,int k)
{
    int t=size[ch[r][0]]+1;
    if(t==k)return r;
    if(t>k)return get_kth(ch[r][0],k);
    return get_kth(ch[r][1],k-t);
}
int find(int r,int k)
{
    int lson=ch[r][0],rson=ch[r][1];
    if(cnt[lson][1]==k&&key[r]<0)
    {
        Splay(r,0);
        return size[ch[root][0]];
    }
    else if(cnt[lson][1]>=k+1)return find(lson,k);
    else return find(rson,k-cnt[lson][1]-(key[r]<0));
}
struct InterValTree
{
    int minv[maxn<<2];
    void build(int o,int l,int r)
    {
        minv[o]=0;
        if(l==r)
        {
            minv[o]=l;
            return;
        }
        int mid=(l+r)>>1;
        build(o<<1,l,mid);
        build(o<<1|1,mid+1,r);
        push_up(o);
    }
    void push_up(int o)
    {
        minv[o]=min(minv[o<<1],minv[o<<1|1]);
    }
    void update(int o,int l,int r,int pos,int flag)
    {
        if(l==r)
        {
            if(flag)minv[o]=INF;
            else minv[o]=l;
            return;
        }
        int mid=(l+r)>>1;
        if(pos<=mid)update(o<<1,l,mid,pos,flag);
        else update(o<<1|1,mid+1,r,pos,flag);
        push_up(o);
    }
}tree;
void debug(int r)
{
    if(!r)return;
    debug(ch[r][0]);
    printf("%d ",key[r]);
    debug(ch[r][1]);
}
void Insert(int pos)
{
    int num=tree.minv[1];
    tree.update(1,1,M,num,1);
    Splay(get_kth(root,pos+1),0);
    Splay(get_kth(root,pos+2),root);
    NewNode(Key_value,ch[root][1],num);

    position[num][0]=Key_value;

    pushup(ch[root][1]);
    pushup(root);
    Splay(Key_value,0);
    int n=cnt[ch[root][0]][0];
    if(cnt[root][1]<=n)
    {
        int m=size[root]-2+1;
        Splay(get_kth(root,m),0);
        Splay(get_kth(root,m+1),root);
        NewNode(Key_value,ch[root][1],-num);
        position[num][1]=Key_value;
    }
    else
    {
        int m=find(root,n);
        Splay(get_kth(root,m),0);
        Splay(get_kth(root,m+1),root);
        NewNode(Key_value,ch[root][1],-num);
        position[num][1]=Key_value;
    }
    pushup(ch[root][1]);
    pushup(root);
}
void Delete(int x)
{
    Splay(x,0);
    int pos=size[ch[x][0]];
    Splay(get_kth(root,pos),0);
    Splay(get_kth(root,pos+2),root);
    pre[Key_value]=0;
    Key_value=0;
    pushup(ch[root][1]);
    pushup(root);
}
void Remove(int x)
{
    Delete(position[x][0]);
    Delete(position[x][1]);
    tree.update(1,1,M,x,0);
}

void Query(int x)
{
    Splay(position[x][0],0);
    Splay(position[x][1],position[x][0]);
    cout<<sum[Key_value]<<endl;;
}
int main()
{
    char op[10];
    int cas=1;
    while(scanf("%d",&M)!=EOF)
    {
        tree.build(1,1,M);
        init();
        printf("Case #%d:\n",cas++);
        for(int i=1;i<=M;i++)
        {
            int x;
            scanf("%s%d",op,&x);
            if(op[0]=='i')Insert(x);
            else if(op[0]=='r')Remove(x);
            else if(op[0]=='q')Query(x);
        }
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值