题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1208
思路:本题可以用线段树或者是SBT树做,用线段树只要找出给定一个数的左极限点和右极限点,然后决策选择哪个点,再用线段树单点更新就可以。 用SBT其实思路和线段树类似。
线段树:
#include <stdio.h>
#include <string.h>
#include <map>
typedef long long LL ;
const int NN = 80010 ;
const int Mod = 1000000 ;
int op[NN] , P[NN] ;
int N ;
std::map<int,int> mp ;
int rev[NN] , cnt ;
int EE[ NN << 2 ] ;
LL inf ;
void update(int l , int r, int idx, int pos , int v ){
if( l == r ){
EE[idx] = v ;
return ;
}
int mid = (l + r) >> 1 ;
if( pos <= mid ) update(l , mid , idx<<1,pos , v ) ;
else update(mid+1, r , idx<<1|1 ,pos ,v) ;
EE[idx] = EE[idx<<1] | EE[idx<<1|1] ;
}
int query_left(int l, int r, int idx, int pos ){
if( EE[idx]==0 ) return -1 ;
if(l == r ) return l ;
int mid = (l + r) >> 1 ;
if( pos <= mid ) return query_left(l , mid , idx<<1 , pos ) ;
else{
int n = query_left( mid+1, r ,idx<<1|1 , pos ) ;
if( n != -1 ) return n ;
return query_left( l , mid , idx<<1 , pos ) ;
}
}
int query_right(int l ,int r, int idx, int pos ){
if( 0 == EE[idx] ) return -1 ;
if( l == r ) return l ;
int mid = (l + r) >> 1 ;
if( pos <= mid ){
int n = query_right(l , mid , idx<<1 , pos ) ;
if( n!=-1 ) return n ;
return query_right( mid+1 , r ,idx<<1|1 , pos ) ;
}
else return query_right( mid+1 ,r , idx<<1|1 , pos ) ;
}
void solve(){
memset( EE , 0 ,sizeof(EE) ) ;
int f , left , right ;
LL ans = 0 ;
for(int i=0;i<N;i++){
if( EE[1] == 0 ){
f = op[i] ;
update(1 , cnt , 1 , mp[P[i]] , 1 ) ;
}
else{
if( f == op[i] ){
update(1 , cnt , 1 , mp[P[i]] , 1 ) ;
}
else{
left = query_left(1 , cnt , 1 , mp[P[i]] ) ;
right = query_right(1 , cnt , 1 , mp[P[i]] ) ;
LL up , down ;
if( left == -1 ) down = inf ;
else down = (LL)P[i] - (LL)rev[left] ;
if( right == -1 ) up = inf ;
else up = (LL)rev[ right ] - (LL)P[i] ;
if( up >= down ){
ans += down ;
update( 1 , cnt , 1 , left , 0 ) ;
}
else{
ans += up ;
update(1 , cnt , 1 , right , 0 ) ;
}
ans %= Mod ;
}
}
}
printf("%lld\n",ans);
}
int main(){
inf = 1e15 ;
while( scanf("%d",&N) == 1 ){
mp.clear() ;
for(int i=0;i<N;i++){
scanf("%d %d",&op[i] ,&P[i]);
mp[ P[i] ] = 1 ;
}
std::map<int,int>::iterator it = mp.begin() ;
cnt = 0 ;
for( ; it!=mp.end();++it){
it->second = ++cnt ;
rev[cnt] = it->first ;
}
solve() ;
}
return 0 ;
}
SBT
#include <stdio.h>
#include <string.h>
typedef long long LL ;
const int NN = 80010 ;
const int Mod = 1000000 ;
int left[NN] , right[NN] , size[NN] , key[NN] ;
int T , N , node ;
void left_rotate(int &T){
int k = right[T] ;
right[T] = left[k] ;
left[k] = T ;
size[k] = size[T] ;
size[T] = size[left[T]] + size[right[T]] + 1 ;
T = k ;
}
void right_rotate(int &T){
int k = left[T] ;
left[T] = right[k] ;
right[k] = T;
size[k] = size[T] ;
size[T] = size[left[T]] + size[right[T]] + 1 ;
T = k ;
}
void Maintain(int &T , int f){
if( f == 1 ){
if( size[right[right[T]]] > size[left[T]] )
left_rotate( T );
else if( size[left[right[T]]] > size[left[T]] )
right_rotate(right[T]) , left_rotate(T) ;
else
return ;
}
else{
if( size[left[left[T]]] > size[right[T]] )
right_rotate( T );
else if( size[right[left[T]]] > size[right[T]] )
left_rotate( left[T] ) , right_rotate(T) ;
else
return ;
}
Maintain( left[T] , 0 ) ;
Maintain( right[T] , 1 ) ;
Maintain( T , 0 ) ;
Maintain( T , 1 ) ;
}
void add(int &T , int v){
T = ++node ;
left[T] = right[T] = 0 ;
size[T] = 1 ; key[T] = v ;
}
void insert(int &T , int v){
if( T == 0 ){
add( T , v ) ;
return ;
}
size[T]++ ;
if( v < key[T] )
insert( left[T] , v ) ;
else
insert( right[T] , v ) ;
Maintain( T, v >= key[T] ) ;
}
int query_left(int &T, int v){
if(T == 0) return -1 ;
if( v <= key[T] )
return query_left( left[T] , v ) ;
else{
int n = query_left( right[T] , v ) ;
if( n != -1 ) return n ;
return key[T] ;
}
}
int query_right(int &T, int v){
if(T == 0) return -1 ;
if( v >= key[T] ) return query_right( right[T] , v ) ;
else{
int n = query_right( left[T] , v ) ;
if( n!=-1 ) return n ;
return key[T] ;
}
}
void Erase(int & , int ) ;
void remove(int &T){
if( left[T] && right[T] ){
int tmp = right[T] ;
while( left[tmp] ) tmp = left[tmp] ;
key[T] = key[tmp] ;
Erase( right[T] , key[T] ) ;
}
else{
if( left[T] == 0 )
T = right[T] ;
else
T = left[T] ;
}
}
void Erase(int &T, int v ){
if(T == 0) return ;
size[T]-- ;
if(v==key[T]){
remove(T) ;
return ;
}
else if( v<key[T] )
Erase(left[T] , v) ;
else
Erase(right[T] , v ) ;
}
int main(){
int ff ,a , b ;
LL ans , inf = 1000000000000000LL ;
while( scanf("%d",&N) == 1 ){
ans = T = node = left[0] = right[0] = size[0] = 0 ;
for(int i=0;i<N;i++){
scanf("%d%d",&a,&b);
if( T == 0 ){
ff = a ;
insert(T , b);
}
else{
if(ff == a)
insert( T , b ) ;
else{
int down = query_left( T , b ) ;
int up = query_right(T , b) ;
LL d1 ,d2 ;
d1 = down==-1?inf:b-down ;
d2 = up==-1?inf:up-b ;
if( d1 <= d2 ){
ans += d1 ;
Erase(T , down) ;
}
else{
ans += d2 ;
Erase(T , up) ;
}
ans %= Mod ;
}
}
}
printf("%lld\n",ans);
}
return 0 ;
}