您的位置:首页 > 其它

BZOJ 3224 普通平衡树 treap or vector

2016-01-01 13:05 435 查看
很明显这是一道treap的题,但看了黄学长的博客后,也让我大开了眼界,没想到vector也能用那么短的编码量把这道题AC,着实令我敬佩。这也提醒了我 STL 的重要性。 的确, 对于C++ 选手来说,如果能灵活地使用 STL, 的确受益匪浅(虽然速度可能比其他的慢一点,但正确性和编程复杂度都比其他的好,如果时间复杂度允许,在紧张的编程时间内,STL或许会是不错的选择)。

这是STL(vector)的代码, 用到了 insert, lowerr_bound, erase 等函数, 加油。(1700多毫秒)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<set>
#include<vector>
#include<algorithm>
#define inf 1000000000
using namespace std;

inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n;
vector<int> a;

void insert(int x)
{
a.insert(upper_bound(a.begin(),a.end(),x),x);
return;
}

void del(int x)
{
a.erase(lower_bound(a.begin(),a.end(),x));
return;
}
int find(int x)
{
return lower_bound(a.begin(),a.end(),x)-a.begin()+1;
}
int main()
{
n=read();
a.reserve(200000);
int f,x;
for(int i=1;i<=n;i++)
{
f=read();x=read();
switch(f)
{
case 1:insert(x);break;
case 2:del(x);break;
case 3:printf("%d\n",find(x));break;
case 4:printf("%d\n",a[x-1]);break;
case 5:printf("%d\n",*--lower_bound(a.begin(),a.end(),x));break;
case 6:printf("%d\n",*upper_bound(a.begin(),a.end(),x));break;
}
}
return 0;
}


接下来肯定是treap 的代码了,orz 黄学长。从他那里,着实学了不少好东西。(300多毫秒,比上面快多了吧!这个时间差距主要是因为查如何删除造成的)。

#include<cstdio>
#include<iostream>
#include<cstdlib>
#define rep(i,j,k) for(int i = j; i <= k; i++)
using namespace std;

struct node{
int c[2], w, s, v, rnd;
} tr[100005];

int n, ans, root, size;

int read()
{
int s = 0, t = 1; char c= getchar();
while( !isdigit(c) ){
if( c == '-' ) t = -1; c = getchar();
}
while( isdigit(c) ){
s = s * 10 + c - '0'; c = getchar();
}
return s * t;
}

void update(int k)
{
tr[k].s = tr[tr[k].c[0]].s + tr[tr[k].c[1]].s + tr[k].w;
}

void rorate(int&k,int d)
{
int y = tr[k].c[d^1]; tr[k].c[d^1] = tr[y].c[d];
tr[y].c[d] = k; update(k), update(y), k = y;
}

void insert(int&k,int x)
{
if( k == 0 ){
++size; k = size; tr[k].c[0] = tr[k].c[1] = 0, tr[k].s = tr[k].w = 1, tr[k].v = x, tr[k].rnd = rand();
return;
}
tr[k].s++;
if( x == tr[k].v ) tr[k].w++;
else if( x < tr[k].v) {
insert(tr[k].c[0],x);
if( tr[tr[k].c[0]].rnd > tr[k].rnd )rorate(k,1);
}
else {
insert(tr[k].c[1],x);
if( tr[tr[k].c[1]].rnd > tr[k].rnd ) rorate(k,0);
}
}

void delt(int&k,int x)
{
if( !k ) return;
if( tr[k].v == x ){
if( tr[k].w > 1 ) {
tr[k].w--, tr[k].s--;  return;
}
else {
if( tr[k].c[0] * tr[k].c[1] == 0 ) k = tr[k].c[0] + tr[k].c[1];
else {
if( tr[tr[k].c[0]].rnd > tr[tr[k].c[1]].rnd ) {
rorate(k,1); delt(k,x);
}
else {
rorate(k,0); delt(k,x);
}
}
}
}
else {
tr[k].s--;
if( x < tr[k].v ) delt(tr[k].c[0],x);
else delt(tr[k].c[1],x);
}
}

int query_rank(int k,int x)
{
if( !k ) return 0;
if( tr[k].v == x ) return tr[tr[k].c[0]].s + 1;
else if( tr[k].v < x ) return tr[tr[k].c[0]].s + tr[k].w + query_rank(tr[k].c[1],x);
else return query_rank(tr[k].c[0],x);
}

int query_num(int k,int num)
{
if( !k ) return 0;
if( tr[tr[k].c[0]].s >= num ) return query_num(tr[k].c[0],num);
else if( tr[tr[k].c[0]].s + tr[k].w < num ) return query_num(tr[k].c[1],num-tr[tr[k].c[0]].s - tr[k].w);
else return tr[k].v;
}

void query_pre(int k,int x)
{
if( !k ) return;
if( tr[k].v < x ){
ans = k, query_pre(tr[k].c[1],x);
}
else  query_pre(tr[k].c[0],x);
}

void query_suc(int k,int x)
{
if( !k ) return;
if( tr[k].v > x ){
ans = k, query_suc(tr[k].c[0],x);
}
else  query_suc(tr[k].c[1],x);
}

int main()
{
scanf("%d",&n);
int opt,x;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&opt,&x);
switch(opt)
{
case 1:insert(root,x);break;
case 2:delt(root,x);break;
case 3:printf("%d\n",query_rank(root,x));break;
case 4:printf("%d\n",query_num(root,x));break;
case 5:ans=0;query_pre(root,x);printf("%d\n",tr[ans].v);break;
case 6:ans=0;query_suc(root,x);printf("%d\n",tr[ans].v);break;
}
}
return 0;
}


3224: Tyvj 1728 普通平衡树

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 5783 Solved: 2381
[Submit][Status][Discuss]

Description

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)

Input

第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)

Output

对于操作3,4,5,6每行输出一个数,表示对应答案

Sample Input

10

1 106465

4 1

1 317721

1 460929

1 644985

1 84185

1 89851

6 81968

1 492737

5 493598

Sample Output

106465

84185

492737

HINT

1.n的数据范围:n<=100000

2.每个数的数据范围:[-1e7,1e7]

Source

平衡树
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: