您的位置:首页 > 其它

POJ 2886 Who Gets the Most Candies? 线段树

2012-06-30 22:32 549 查看
http://poj.org/problem?id=2886

题意:

N个人玩一个游戏,每个人都有一个weight ,游戏从第K个人开始,第一轮标号为K的人退出游戏,下一个退出的人的编号由上一轮退出的人的weight决定,如果上一轮退出的人的weight

为正,则下一个退出的人是上一轮退出的人的左手边的第weight个人,如果是负数则是右手边

的第weight个人,每个人退出时候都有一个得分,得分是退出的编号的约数的个数,问得分最

高的人能得几分。 N <= 500.000

思路:

分析题目可以看出, 首先题目要求的是得分最高的人的得分,因此我们可以先预处理出所有编

号的得分,然后求出最大的得分,这样问题就变成求一个指定退出编号的人了。然后对于每个

人有一个weight, 现在我们要做的就是如何快速地从一个人求到另外一个人,这样我们可以利

用线段树来求,在N <= 500 000 的情况下, 这个可以在O( nlogn )的算法内求出。

代码:

#include <stdio.h>
#include <string.h>
#define LL(a) ( (a)<<1 )
#define RR(a) ( (a)<<1|1 )

int N , K ;
const int MAXN = 500010 ;
char name[MAXN][11] ;
int val[MAXN] ;
int d_num[MAXN] ;
int _max  , pos ;
int num[MAXN<<2] ;

void cal(){
for(int i=1;i<MAXN;i++)
d_num[i] = 1 ;
for(int i=2;i<MAXN;i++){
for(int j=1;j*i<MAXN;j++){
d_num[ i*j ] ++ ;
}
}
}
void build(int l , int r , int idx ){
int mid = (l + r) >> 1 ;
if(l == r){
num[idx] = 1 ;
return ;
}
build(l , mid , LL(idx) ) ;
build(mid+1, r , RR(idx) ) ;
num[idx] = num[ LL(idx) ] + num[ RR(idx) ] ;
}
int query(int l ,int r, int idx , int a , int b){
if(l==a && r==b){
return num[idx] ;
}
int mid = (l + r) >> 1;
if(b <= mid){
return query( l, mid, LL(idx) , a, b);
}
else if( mid < a ){
return query( mid+1 , r ,RR(idx) , a ,b );
}
else{
return query( l ,mid ,LL(idx) , a , mid ) + query( mid+1, r, RR(idx) , mid+1, b );
}
}
void update1(int l,int r , int idx ,int pos){
if(l == r){
num[idx] -- ;
return  ;
}
int mid = (l + r) >> 1;
if( pos <= mid ){
update1(l , mid , LL(idx) , pos );
}
else{
update1(mid+1, r,  RR(idx) , pos );
}
num[idx] = num[ LL(idx) ] + num[ RR(idx) ] ;
}
int update(int l ,int r , int idx , int vv){
if(l == r){
return l ;
}
int mid = (l + r ) >> 1 ;
if( num[ LL(idx) ] >= vv ){
return update(l ,mid , LL(idx) , vv);
}
else{
return update(mid+1, r , RR(idx) , vv-num[ LL(idx) ] ) ;
}
}

void solve(){
int nn = 1 ;
int now = K ;

while( nn <= N ){
if(nn == pos){
printf("%s %d\n",name[now] , d_num[pos] );
return ;
}
int vv = val[now] ;
int left = N - nn ;
int n1 , n2 ;
if( vv > 0 ){
// go left
n1 = query(1, N , 1 , 1 , now );
update1(1 , N ,1 , now);
n1 -- ;
n2 = left - n1 ;
vv %= left ;
if( vv == 0 ){
if(n1 == 0)
now = update(1 , N ,1 , left) ;
else
now = update(1, N ,1 , n1 ) ;
}
else{
if( vv <= n2 ){
vv = n1 + vv ;
}
else{
vv -= n2 ;
}
now = update(1, N , 1 , vv );
}
}
else{
// go right ;
n1 = query(1 , N , 1 , 1 , now ) ;
update1(1 , N ,1 , now);
n1 --  ;
n2 = left - n1 ;
vv = -vv ;
vv %= left ;
if( vv == 0 ){
if( n2 == 0 ){
now = update(1 , N ,1 , 1 );
}
else{
now = update(1 , N , 1 , n1 + 1 );
}
}
else{
if( vv <= n1 ){
now = update(1, N ,1 ,n1+1-vv);
}
else{
now = update(1 , N ,1 , left-(vv-n1)+1 );
}
}
}
nn++ ;
}
}

int main(){
cal() ;
//freopen("1out.txt","w",stdout) ;
while( scanf("%d %d",&N,&K) == 2){
for(int i=1;i<=N;i++){
scanf("%s %d",name[i] , val+i) ;
}
_max = -1 ;
for(int i=1;i<=N;i++){
if( d_num[i] > _max ){
_max = d_num[i] ;
pos = i ;
}
}
build( 1, N ,1 );
solve() ;
}
return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: