poj2828-Buy Tickets 连接如下:http://poj.org/problem?id=2828
(线段树的经典运用)
题意就是给你一些数字和他们的插入位置,最后输出他们的顺序。看到这道题目,我也没反应过来这道题目和线段树有什么联系,关键是知道也不会用啊,线段树的random域到底用来保存什么好就很纠结了...
这道题目突破点在于,越后面插入的人他的位置越不可能变动,比如最后一个人,他插在哪就站在哪,它的序号不会发生变化。所以最好的办法就是从后往前推。
假设一共有n个人,对于倒数第i个人而言,假设他要插在第k个位置上,那么我只要从前往后数到第k个空位然后插入就好了。后面我已经处理的i-1个人的插入对于他而言没有影响。random域就可以用来保存该段区间的空位数。
核心代码在于:
if( a[i].l == a[i].r )
{
que[a[i].l] = value ;
}
else
if( a[2*i].num >= postn )
{ 如果前段区间的空位数比要插入的位置大
renew( postn , value , 2*i ) ;
}
else
{ 寻找后段区间的插入
renew( postn - a[2*i].num , value , 2*i+1 ) ;
}
a[i].num--;空位数递归 -1
{
que[a[i].l] = value ;
}
else
if( a[2*i].num >= postn )
{ 如果前段区间的空位数比要插入的位置大
renew( postn , value , 2*i ) ;
}
else
{ 寻找后段区间的插入
renew( postn - a[2*i].num , value , 2*i+1 ) ;
}
a[i].num--;空位数递归 -1
这道题目运用的逆序思想很好的解决了这样的插入问题,以前我们只会用链表来解决插入,现在又有了一种新的思路!
最后的代码如下:
#include
#include
#include
#define maxn 200001
int que[maxn] , pos[maxn] , val[maxn] ;
int nn ;
struct point
{
int l , r ;
int num ;
}a[maxn*4];
void init(int le , int ri , int i)
{
int mid ;
a[i].l = le ;
a[i].r = ri ;
if( a[i].l == a[i].r )
{
a[i].num = 1 ;
return ;
}
mid = ( a[i].l + a[i].r )/2 ;
init( le , mid , 2*i ) ;
init( mid+1 , ri , 2*i+1 ) ;
a[i].num = a[2*i].num + a[2*i+1].num ;
}
int renew( int postn , int value , int i )
{///core code - to find the people i's (whose value is "value") insert position(postn).
int mid ;
if( a[i].l == a[i].r )
{
que[a[i].l] = value ;
}
else
if( a[2*i].num >= postn )
{
renew( postn , value , 2*i ) ;
}
else
{
renew( postn - a[2*i].num , value , 2*i+1 ) ;
}
a[i].num--;
return 1 ;
}
int main()
{
int i ;
while( scanf ( "%d" , &nn ) != EOF )
{
for( i = 0 ; i < nn ; i++ )
{
scanf( "%d%d" , &pos[i] , &val[i] ) ;
}init( 1 , nn , 1 );
for( i = nn-1 ; i >= 0 ; i-- )
{
renew( pos[i]+1 , val[i] , 1 ) ;
}
for( i = 1 ; i < nn ; i++ )
{
printf( "%d " , que[i] ) ;
}printf( "%d\n" , que[i] ) ;
}
return 0;
}