ORDERSET - Order statistic set

 

In this problem, you have to maintain a dynamic set of numbers which support the two fundamental operations

  • INSERT(S,x): if x is not in S, insert x into S
  • DELETE(S,x): if x is in S, delete x from S

and the two type of queries

  • K-TH(S) : return the k-th smallest element of S
  • COUNT(S,x): return the number of elements of S smaller than x

Input

  • Line 1: Q (1 ≤ Q ≤ 200000), the number of operations
  • In the next Q lines, the first token of each line is a character I, D, K or C meaning that the corresponding operation is INSERT, DELETE, K-TH or COUNT, respectively, following by a whitespace and an integer which is the parameter for that operation.

If the parameter is a value x, it is guaranteed that 0 ≤ |x| ≤ 109. If the parameter is an index k, it is guaranteed that 1 ≤ k ≤ 109.

Output

For each query, print the corresponding result in a single line. In particular, for the queries K-TH, if k is larger than the number of elements in S, print the word 'invalid'.

Example

Input
8
I -1
I -1
I 2
C 0
K 2
D -1
K 1
K 2 Output
1
2
2
invalid

分析

可以用Treap做,也可以Splay什么的,先用权值线段树水一水,再用Treap水一水。

代码

权值线段树

 #include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm> using namespace std; #define N 200005 struct node
{
int lt, rt, cnt;
}tree[N << ]; void build(int p, int l, int r)
{
node &t = tree[p]; t.lt = l;
t.rt = r;
t.cnt = ; if (l == r)
return; int mid = (l + r) >> ; build(p << , l, mid);
build(p << | , mid + , r);
} void insert(int p, int pos, int val)
{
node &t = tree[p]; t.cnt += val; if (t.lt == t.rt)
return; int mid = (t.lt + t.rt) >> ; if (pos <= mid)
insert(p << , pos, val);
else
insert(p << | , pos, val);
} int query(int p, int l, int r)
{
if (l > r)return ; node &t = tree[p]; if (t.lt == l && t.rt == r)
return t.cnt; int mid = (t.lt + t.rt) >> ; if (r <= mid)
return query(p << , l, r);
if (l > mid)
return query(p << | , l, r);
return query(p << , l, mid) + query(p << | , mid + , r);
} int rnk(int p, int rk)
{
node &t = tree[p]; if (t.lt == t.rt)
return t.lt; if (tree[p << ].cnt >= rk)
return rnk(p << , rk); else
return rnk(p << | , rk - tree[p << ].cnt);
} int n;
int a[N];
int b[N]; char s[N][]; signed main(void)
{
scanf("%d", &n); for (int i = ; i <= n; ++i)
scanf("%s%d", s[i], &a[i]); memcpy(b, a, sizeof(b)); sort(b + , b + + n); int m = unique(b + , b + + n) - b; build(, , m); for (int i = ; i <= n; ++i)if (s[i][] != 'K')
a[i] = lower_bound(b + , b + m, a[i]) - b; for (int i = ; i <= n; ++i)
{
char &c = s[i][]; if (c == 'I')
{
if (!query(, a[i], a[i]))
insert(, a[i], );
}
else if (c == 'D')
{
if (query(, a[i], a[i]))
insert(, a[i], -);
}
else if (c == 'K')
{
if (query(, , m) >= a[i])
printf("%d\n", b[rnk(, a[i])]);
else printf("invalid\n");
}
else if (c == 'C')
{
printf("%d\n", query(, , a[i] - ));
}
}
}

SegTree.cpp

Treap

 #include <bits/stdc++.h>

 class treap
{
private: struct node
{
int key;
int tag;
int siz;
node *lson;
node *rson;
node(int k = , int t = rand()) :
key(k), tag(t), siz(), lson(), rson() {};
}; int getSize(node *&t)
{
if (t == NULL)return ;
t->siz = ;
if (t->lson)
t->siz += t->lson->siz;
if (t->rson)
t->siz += t->rson->siz;
return t->siz;
} void rotateLeft(node *&t)
{
node *r = t->rson;
t->rson = r->lson;
r->lson = t;
getSize(t);
getSize(r);
t = r;
} void rotateRight(node *&t)
{
node *l = t->lson;
t->lson = l->rson;
l->rson = t;
getSize(t);
getSize(l);
t = l;
} void insertNode(node *&t, int k)
{
if (t == NULL)
t = new node(k);
else
{
if (k < t->key)
{
insertNode(t->lson, k);
if (t->lson->tag > t->tag)
rotateRight(t);
}
else if (k > t->key)
{
insertNode(t->rson, k);
if (t->rson->tag > t->tag)
rotateLeft(t);
}
}
getSize(t);
} void deleteNode(node *&t)
{
if (t->lson == NULL)
t = t->rson;
else if (t->rson == NULL)
t = t->lson;
else
{
if (t->lson->tag > t->rson->tag)
rotateRight(t), deleteNode(t->rson);
else
rotateLeft(t), deleteNode(t->lson);
}
getSize(t);
} void deleteNode(node *&t, int k)
{
if (t != NULL)
{
if (k == t->key)
deleteNode(t);
else if (k < t->key)
deleteNode(t->lson, k);
else
deleteNode(t->rson, k);
getSize(t);
}
} node *findElement(node *&t, int k)
{
if (k == t->key)
return t;
else if (k < t->key)
return findElement(t->lson, k);
else
return findElement(t->rson, k);
} node *kthElement(node *&t, int k)
{
int leftSize = getSize(t->lson);
if (k == leftSize + )
return t;
else if (k <= leftSize)
return kthElement(t->lson, k);
else
return kthElement(t->rson, k - leftSize - );
} int countSmaller(node *&t, int k)
{
if (t == NULL)return ;
if (k == t->key)
return getSize(t->lson);
else if (k < t->key)
return countSmaller(t->lson, k);
else
return countSmaller(t->rson, k) + getSize(t->lson) + ;
} int countBigger(node *&t, int k)
{
if (t == NULL)return ;
if (k == t->key)
return getSize(t->rson);
else if (k > t->key)
return countBigger(t->rson, k);
else
return countBigger(t->lson, k) + getSize(t->rson) + ;
} node *treapRoot; public: treap(void)
{
treapRoot = NULL;
srand(time() + );
} int size(void)
{
return getSize(treapRoot);
} void insert(int key)
{
insertNode(treapRoot, key);
} void erase(int key)
{
deleteNode(treapRoot, key);
} int kthElement(int key)
{
return kthElement(treapRoot, key)->key;
} int countSmaller(int key)
{
return countSmaller(treapRoot, key);
} }t; signed main(void)
{
using namespace std; int n; scanf("%d", &n); char s[]; int num; while (n--)
{
scanf("%s%d", s, &num); char c = s[]; if (c == 'I')
t.insert(num);
else if (c == 'D')
t.erase(num);
else if (c == 'C')
printf("%d\n", t.countSmaller(num));
else
{
if (num <= t.size())
printf("%d\n", t.kthElement(num));
else
puts("invalid");
}
}
}

Treap.cpp

@Author: YouSiki

SPOJ ORDERSET - Order statistic set的更多相关文章

  1. SPOJ 3273 - Order statistic set , Treap

    点击打开链接 题意: 集合S支持一下四种操作:   INSERT(S,x) :   假设S中没有x,则插入x DELETE(S,x):  假设S中有x,则删除x K-TH(S):           ...

  2. Order Statistic

    目录 The Order Statistic 引理1 的一些基本性质 顺序统计量的分布 顺序统计量的条件分布 特殊分布的特殊性质 Order Statistic The Order Statistic ...

  3. (转)約瑟夫問題的兩個O(log n)解法

    約瑟夫問題的兩個O(log n)解法 這個是學習編程時的一個耳熟能詳的問題了: n個人(編號爲0,1,...,n-1)圍成一個圈子,從0號開始依次報數,每數到第m個人,這個人就得自殺, 之後從下個人開 ...

  4. extSourceStat_7Day_Orders.php

    <?php /** Log文件格式2012/7/4 列号 字段含义 取值 ------------------------------------------------------------ ...

  5. Heapsort 堆排序算法详解(Java实现)

    Heapsort (堆排序)是最经典的排序算法之一,在google或者百度中搜一下可以搜到很多非常详细的解析.同样好的排序算法还有quicksort(快速排序)和merge sort(归并排序),选择 ...

  6. 【转】ActiveMQ与虚拟通道

    郑重提示,本文转载自http://shift-alt-ctrl.iteye.com/blog/2065436 ActiveMQ提供了虚拟通道的特性(Virtual Destination),它允许一个 ...

  7. SSE图像算法优化系列二十三: 基于value-and-criterion structure 系列滤波器(如Kuwahara,MLV,MCV滤波器)的优化。

    基于value-and-criterion structure方式的实现的滤波器在原理上其实比较简单,感觉下面论文中得一段话已经描述的比较清晰了,直接贴英文吧,感觉翻译过来反而失去了原始的韵味了. T ...

  8. CF-1055E:Segments on the Line (二分&背包&DP优化)(nice problem)

    You are a given a list of integers a 1 ,a 2 ,…,a n  a1,a2,…,an and s s of its segments [l j ;r j ] [ ...

  9. 算法导论-顺序统计-快速求第i小的元素

    目录 1.问题的引出-求第i个顺序统计量 2.方法一:以期望线性时间做选择 3.方法二(改进):最坏情况线性时间的选择 4.完整测试代码(c++) 5.参考资料 内容 1.问题的引出-求第i个顺序统计 ...

随机推荐

  1. Python的高级特性5:谈谈python的动态属性

    正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性. 看下面一种常见的get/set操作 In [174]: class ...

  2. 用django实现一个微信图灵机器人

    微信的post请求格式是xml,所以django需要做的就是将xml请求解析出来,把content发送到图灵机器人接口, 接口返回的json数据把主要内容给解析出来,然后重新封装成xml返回给微信客户 ...

  3. Java核心技术点之内部类

    1. 为什么要使用内部类     内部类就是定义在一个类内部的类,那么为什么要使用内部类呢?主要原因有以下几点:第一,内部类中定义的方法能访问到它所在外部类的私有属性及方法:第二,外部类无法实现对同一 ...

  4. Java设计模式之-----工厂模式(简单工厂,抽象工厂)

    一.工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的. 工厂模式在<Java与模式>中分为三类:1)简单工厂模式(Simple Factor ...

  5. 开发环境python

    python开发环境搭建   虽然网上有很多python开发环境搭建的文章,不过重复造轮子还是要的,记录一下过程,方便自己以后配置,也方便正在学习中的同事配置他们的环境. 1.准备好安装包 1)上py ...

  6. Android的媒体管理框架:Glide

    Glide是一个高效.开源. Android设备上的媒体管理框架,它遵循BSD.MIT以及Apache 2.0协议发布.Glide具有获取.解码和展示视频剧照.图片.动画等功能,它还有灵活的API,这 ...

  7. c++返回值 注意事项

    1.不要返回指向局部变量或临时对象的引用.函数执行完毕后,局部变量和临时对象会消失,引用将指向不存在的数据 2.返回指向const对象的引用 使用const引用的常见原因是旨在提高效率,但对于何时采用 ...

  8. c8051f320学习,单片机不外乎时钟、IO、串口、USB等外设用法

      时钟 IO(输入.输出,如何配置) IO   数字和模拟资源可以通过25个I/O 引脚(C805 1F3 2 0 ),每个端口引脚都可以被定义为 通用I/O(GPIO)或 0 模拟输入 所有端口I ...

  9. .NET基于Redis缓存实现单点登录SSO的解决方案

    一.基本概念 最近公司的多个业务系统要统一整合使用同一个登录,这就是我们耳熟能详的单点登录,现在就NET基于Redis缓存实现单点登录做一个简单的分享. 单点登录(Single Sign On),简称 ...

  10. APP架子迁移指南(二)

    接上一篇,这一篇开始用android来解释MVP概念.八股式的架子结构和命名规范.我在准备这篇文章的时候还看到不少在MVP基础上衍生的架子思路,底子是MVP没错,但命名有区别.复杂度变了.架子也用到了 ...