POJ 2886 Who Gets the Most Candies? 线段树。。还有方向感

时间:2023-03-08 23:56:16
POJ 2886 Who Gets the Most Candies? 线段树。。还有方向感

这道题不仅仅是在考察线段树,还他妹的在考察一个人的方向感。。。。

和线段树有关的那几个函数写了一遍就对了,连改都没改,一直在转圈的问题的出错。。。。

题意:从第K个同学开始,若K的数字为正 则往右转,否则往左转,转到的那同学出圈,知道剩下最后一个人。

输出得到蛋糕最多的人的名字和块数。

线段树的节点中存的是这一段内还有几个人没有跳出,思路很简单,详见注释。

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cmath>
#include <algorithm> using namespace std; int ncd[500010]; struct N
{
int c;
char n[11];
}pla[500010]; struct T
{
int l,r,sur;
}st[2000010]; void init(int l,int r,int site)//初始化线段树
{
st[site].l = l;
st[site].r = r;
st[site].sur = r-l+1;//开始时没有人跳出
if(l == r)
return ;
int mid = (l+r)>>1; init(l,mid,site<<1);
init(mid+1,r,site<<1|1);
} int F,Max; int updata(int m,int site,int R)
{
if(st[site].l == st[site].r)//此时已经找到了具体的人
{
st[site].sur--;//此段中有一人跳出 if(Max < ncd[R]) //比较得到蛋糕书的多少
{
F = st[site].l;
Max = ncd[R];
}
return pla[st[site].l].c;//返回卡片上的值
} int ln = site<<1,rn = site<<1|1;
//如果前半的段的人数 >= m 说明要找的人就在前半段
//反之 就在后半段
st[site].sur--;//此段中有一人跳出 if(m <= st[ln].sur)
{
updata(m,ln,R);
}
else
{
updata(m-st[ln].sur,rn,R);
}
} int main()
{
int i,j,k,n = sqrt(500000),m = 500000;
int tempr;
int tempc; for(i = 1;i <= n; ++i)
{
for(j = i;j <= m; ++j)
{
k = i*j;
if(k <= 500000)
{
if(i == j)
ncd[k]++;
else
ncd[k] += 2;
}
else break;
}
} while(scanf("%d %d",&n,&k) != EOF)
{
for(i = 1;i <= n; ++i)
{
scanf("%*c%s%d",pla[i].n,&pla[i].c);
} init(1,n,1); tempr = k; //tempr为第i个要被删除的人在删除i-1个人之后的位置
//tempc为第i个的人的卡片上的值 F = k;
Max = 1;
for(i = 1;; ++i)
{
tempc = updata(tempr,1,i);
if(i == n)
break; m = n-i;//m为剩下的人数 //下面讨论下一个要跳出的是谁。。。。错了N次。。。。
if(tempc > 0)//往右转
{
tempc %= m;
if(tempc == 0)//取余为零说明 tempc 为 m 的 倍数
tempc = m;
if(tempc <= m-tempr+1)//m-tempr+1 为tempr之后的人数
{
tempr += tempc - 1;
}
else
{
tempr = tempc - m+tempr-1;
}
}
else//往左转
{
tempc = - tempc;
tempc %= m;
if(tempc == 0)
tempc = m;
if(tempc <= tempr-1)
{
tempr = tempr-tempc;
}
else
{
tempr += m-tempc;
}
}
}
printf("%s %d\n",pla[F].n,Max);
}
return 0;
}