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. 微信v3 JSAPI最新接口错误 get_brand_wcpay_request:fail

    WxPay.JsApiPay.php文件下 原始接口代码 /** * * 获取jsapi支付的参数 * @param array $UnifiedOrderResult 统一支付接口返回的数据 * @ ...

  2. PAT 1005. 继续(3n+1)猜想 (25) JAVA

    当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程中遇到的每一个数.例如对n=3进行验证的时候,我们需要计算3.5.8.4.2.1,则当我们对n=5.8.4.2进行验证的时候,就可以直接 ...

  3. SQL GETDATE()日期格式化函数

    Sql Server 中一个非常强大的日期格式化函数 Select CONVERT(varchar(100), GETDATE(), 0): 05 16 2006 10:57AMSelect CONV ...

  4. linux查看出口ip 及w3m字符浏览器

    Linux 查看服务器出口IP    字符浏览器: http://wiki.ubuntu.org.cn/W3m

  5. swift-sharesdk集成微信、Facebook第三方登录

    好久没有写博客了.最近忙得没有时间更新博客,很忙很忙. 今天就把自己做过的第三方集成和大家分享一下,请大家多多指教. 第一步: 一.获取AppKey(去官方平台注册) 二.下载SDK 三.快速集成 第 ...

  6. 数据字典生成工具之旅(7):NVelocity实现代码生成器

    这个系统好久没有更新了,人也慢慢变懒了,从现在开始每个月至少写三篇文章,欢迎大家监督.对了预告一下,该系列完成以后将为大家带来WebApp开发系列篇,敬请期待.先上几张图,放在文章最后面欢迎预览! 本 ...

  7. ASP.NET MVC3入门教程之ajax交互

    本文转载自:http://www.youarebug.com/forum.php?mod=viewthread&tid=100&extra=page%3D1 随着web技术的不断发展与 ...

  8. 用canvas 实现个图片三角化(LOW POLY)效果

    之前无意中看到Ovilia 用threejs做了个LOW POLY,也就是图片平面三角化的效果,觉得很惊艳,然后就自己花了点时间尝试了一下. 我是没怎么用过threejs,所以就直接用canvas的2 ...

  9. OpenFlow

    What is OpenFlow? OpenFlow is an open standard that enables researchers to run experimental protocol ...

  10. android服务之启动方式

    服务有两种启动方式 通过startService方法来启动 通过bindService来开启服务 布局文件 在布局文件中我们定义了四个按键来测试这两种方式来开启服务的不同 <?xml versi ...