BZOJ 3196: Tyvj 1730 二逼平衡树( 树套树 )

这道题做法应该很多吧....

我用了线段树套treap....

--------------------------------------------------------------------------------------------------------------

#include<cstdio>

#include<algorithm>

#include<cstring>

#include<cstdlib>

#include<iostream>

#define rep( i , n ) for( int i = 0 ; i < n ; ++i )

#define clr( x , c ) memset( x , c , sizeof( x ) )

#define Rep( i , n ) for( int i = 1 ; i <= n ; ++i )

#define M( l , r ) ( ( ( l ) + ( r ) ) >> 1 )

using namespace std;

const int maxn = 50000 + 5;

const int maxnode = 1500000;

const int inf = 1e9;

const unsigned int A = 654321 , B = 54321;

int seq[ maxn ] , mn , mx , n;

unsigned int P = 820;

// treap node

struct Node {

Node* ch[ 2 ];

int s , v;

unsigned int r;

Node() : s( 0 ) { }

inline void upd() {

s = ch[ 0 ] -> s + ch[ 1 ] -> s + 1;

}

} pool[ maxnode ] , *pt = pool , *null = pt++;

Node* newNode( int v = 0 ) {

pt -> v = v;

( P *= A ) += B;

pt -> r = P;

pt -> s = 1;

pt -> ch[ 0 ] = pt -> ch[ 1 ] = null;

return pt++;

}

struct treap {

Node* root;

treap() {

root = null;

}

void rot( Node* &t , int d ) {

Node* k = t -> ch[ d ^ 1 ];

t -> ch[ d ^ 1 ] = k -> ch[ d ];

k -> ch[ d ] = t;

t -> upd() , k -> upd();

t = k;

}

void ins( Node* &t , int v ) {

if( t == null )

t = newNode( v );

else {

int d = v > t -> v;

ins( t -> ch[ d ] , v );

if( t -> ch[ d ] -> r > t -> r )

rot( t , d ^ 1 );

}

t -> upd();

}

void del( Node* &t , int v ) {

int d = t -> v == v ? -1 : ( t -> v < v );

if( d == -1 ) {

if( t -> ch[ 0 ] != null & t -> ch[ 1 ] != null ) {

int h = t -> ch[ 0 ] -> r > t -> ch[ 1 ] -> r;

rot( t , h ) , del( t -> ch[ h ] , v );

} else

t = t -> ch[ 0 ] == null ? t -> ch[ 1 ] : t -> ch[ 0 ];

} else

del( t -> ch[ d ] , v );

if( t != null ) t -> upd();

}

int select( int k ) {

for( Node* t = root ; ; ) {

int s = t -> ch[ 0 ] -> s + 1;

if( k == s + 1 ) return t -> v;

if( k < s )

t = t -> ch[ 0 ];

else

k -= s + 1 , t = t -> ch[ 1 ];

}

}

int rank( int v ) {

int ans = 0;

for( Node* t = root ; t != null ; ) {

if( t -> v < v )

ans += t -> ch[ 0 ] -> s + 1 , t = t -> ch[ 1 ];

else

t = t -> ch[ 0 ];

}

return ans;

}

int pred( int v ) {

int ans = -inf;

for( Node* t = root ; t != null ; ) {

if( t -> v < v )

ans = max( ans , t -> v ) , t = t -> ch[ 1 ];

else

t = t -> ch[ 0 ];

}

return ans;

}

int succ( int v ) {

int ans = inf;

for( Node* t = root ; t != null ; ) {

if( t -> v > v )

ans = min( t -> v , ans ) , t = t -> ch[ 0 ];

else

t = t -> ch[ 1 ];

}

return ans;

}

} TREAP[ maxn << 1 ] , *pit = TREAP;

// segment tree node

struct node {

node *l , *r;

treap* x;

} mem[ maxn << 1 ] , *pT = mem , *Rt;

int L , R , v;

void build( node* t , int l , int r ) {

t -> x = pit++;

for( int i = l ; i <= r ; i++ )

t -> x -> ins( t -> x -> root , seq[ i ] );

if( r > l ) {

int m = M( l , r );

build( t -> l = pT++ , l , m );

build( t -> r = pT++ , m + 1 , r );

}

}

void change( node* t , int l , int r ) {

if( r < L || l > L ) return;

t -> x -> del( t -> x -> root , seq[ L ] );

t -> x -> ins( t -> x -> root , v );

if( l == r ) return;

int m = M( l , r );

L <= m ? change( t -> l , l , m ) : change( t -> r , m + 1 , r );

}

int rank( node* t , int l , int r ) {

if( L <= l && r <= R )

return t -> x -> rank( v );

int m = M( l , r );

return ( L <= m ? rank( t -> l , l , m ) : 0 ) +

( m < R ? rank( t -> r , m + 1 , r ) : 0 );

}

int pred( node* t , int l , int r ) {

if( L <= l && r <= R )

return t -> x -> pred( v );

int m = M( l , r );

if( R <= m ) return pred( t -> l , l , m );

else if( L > m ) return pred( t -> r , m + 1 , r );

else return max( pred( t -> l , l , m ) , pred( t -> r , m + 1 , r ) );

}

int succ( node* t , int l , int r ) {

if( L <= l && r <= R )

return t -> x -> succ( v );

int m = M( l , r );

if( R <= m ) return succ( t -> l , l , m );

else if( L > m ) return succ( t -> r , m + 1 , r );

else return min( succ( t -> l , l , m ) , succ( t -> r , m + 1 , r ) );

}

int select( int k ) {

int l = mn , r = mx , ans;

while( l <= r ) {

v = M( l , r );

int h = rank( Rt , 1 , n );

if( rank( Rt , 1 , n ) < k )

ans = v , l = v + 1;

else

r = v - 1;

}

return ans;

}

inline void read( int &x ) {

x = 0;

int sign = 1;

char c = getchar();

for( ; ! isdigit( c ) ; c = getchar() )

if( c == ‘-‘ ) sign = -1;

for( ; isdigit( c ) ; c = getchar() )

x = x * 10 + c - ‘0‘;

x *= sign;

}

int main() {

// freopen( "test.in" , "r" , stdin );

int m;

cin >> n >> m;

Rep( i , n ) {

read( seq[ i ] );

mn = i == 1 ? seq[ i ] : min( seq[ i ] , mn );

mx = i == 1 ? seq[ i ] : max( seq[ i ] , mx );

}

build( Rt = pT++ , 1 , n );

int opt;

while( m-- ) {

read( opt ) , read( L );

switch( opt ) {

case 1 : read( R ); read( v ); printf( "%d\n" , rank( Rt , 1 , n ) + 1 ); break;

case 2 : read( R ); read( v ); printf( "%d\n" , select( v ) ); break;

case 3 : read( v ); change( Rt , 1 , n ); seq[ L ] = v; mn = min( v , mn ); mx = max( mx , v ); break;

case 4 : read( R ); read( v ); printf( "%d\n" , pred( Rt , 1 , n ) ); break;

case 5 : read( R ); read( v ); printf( "%d\n" , succ( Rt , 1 , n ) ); break;

}

}

return 0;

}

--------------------------------------------------------------------------------------------------------------

3196: Tyvj 1730 二逼平衡树

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1324  Solved: 562
[Submit][Status][Discuss]

Description

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)

Input

第一行两个数 n,m 表示长度为n的有序序列和m个操作
第二行有n个数,表示有序序列
下面有m行,opt表示操作标号
若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名
若opt=2 则为操作2,之后有三个数l,r,k 表示查询区间[l,r]内排名为k的数
若opt=3 则为操作3,之后有两个数pos,k 表示将pos位置的数修改为k
若opt=4 则为操作4,之后有三个数l,r,k 表示查询区间[l,r]内k的前驱
若opt=5 则为操作5,之后有三个数l,r,k 表示查询区间[l,r]内k的后继

Output

对于操作1,2,4,5各输出一行,表示查询结果

Sample Input

9 6
4 2 2 1 9 4 0 1 1
2 1 4 3
3 4 10
2 1 4 3
1 2 5 9
4 3 9 5
5 2 8 5

Sample Output

2
4
3
4
9

HINT

1.n和m的数据范围:n,m<=50000

2.序列中每个数的数据范围:[0,1e8]

3.虽然原题没有,但事实上5操作的k可能为负数

Source

时间: 2024-12-28 14:16:56

BZOJ 3196: Tyvj 1730 二逼平衡树( 树套树 )的相关文章

bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,

BZOJ 3196 Tyvj 1730 二逼平衡树 ——树状数组套主席树

[题目分析] 听说是树套树.(雾) 怒写树状数组套主席树,然后就Rank1了.23333 单点修改,区间查询+k大数查询=树状数组套主席树. [代码] #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <set> #include <map> #include <string> #include <alg

bzoj 3196: Tyvj 1730 二逼平衡树

我操,,,,我记得这个sb题,,搞了一整天,(吐槽,本来开心去洛谷提交,结果不一样,mdzz) 树套树,,,各种套... 都是在区间内最基本的查询 1 #include<bits/stdc++.h> 2 #define N 100005 3 #define LL long long 4 #define inf 0x3f3f3f3f 5 using namespace std; 6 inline int ra() 7 { 8 int x=0,f=1; char ch=getchar(); 9 w

3196: Tyvj 1730 二逼平衡树

http://www.lydsy.com/JudgeOnline/problem.php?id=3196 分析: 带区间查询和名次询问,线段树套treap 操作1: 查询k在区间内的排名. 求出k-1的名次+1就是k的名次 操作2:查询区间内排名为k的值. 二分枚举权值,调用操作1 操作3:修改某一位值上的数值. 在树上先删除,再插入 操作4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 操作5.查询k在区间内的后继(后继定义为大于x,且最小的数) 在treap树上遍历 //83516

【BZOJ 3196】Tyvj 1730 二逼平衡树

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 842  Solved: 350 [Submit][Status] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,

【bzoj3196】 Tyvj 1730 二逼平衡树 线段树套Treap

题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) 输入 第一行两个数 n,m 表示长度为n的有序序列和m个操作第二行有n个数,表示有序序列下面有m行,opt表示操作标号若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名若opt=2 则为操

[TYVJ 1730]二逼平衡树 线段树套平衡树

来一发树套树.1A也是很感动QAQ 就是时间复杂度略大.而且好像还有其他打法. 谨以此纪念此类型树套树入门 #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> using namespace std; #define pos(i,a,b) for(int i=(a);i<=(b);i++) #define N 51000 #define size(x) ((x)

Bzoj3196 Tyvj 1730 二逼平衡树

Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3350  Solved: 1324 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作第二行

[Tyvj 1730] 二逼平衡树

先来一发题面QwQ [TYVJ1730]二逼平衡树 Time Limit:2 s   Memory Limit:512 MB Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作第二行有n个数