您的位置:首页 > 其它

POJ 2886 Who Gets the Most Candies? (线段树 约瑟夫环问题变种)

2015-08-16 01:04 441 查看
题目大意:

就是现在有一些孩子坐成一圈, 每个人手里有一个数字(正数或者负数), 孩子们编号1~n, n<=50W

那么, 第一次由编号为K的人跳出, 然后根据其手上的数顺时针或者逆时针决定下一个人

第p个出去的人能得到p的约数个糖果, 问那个人得到的糖果最多

大致思路:

就是约瑟夫环的变种, 每次可能顺时针或者逆时针数出下一个人

那么用线段树的结点表示对应区间内还剩下的人的个数

于是维护区间和就可以了

至于当前在pos位置, 想左边或者向右边移动, 用相对位置来求解

即如果当前要退出的人在剩下的sum个人中的第p个位置, 其退出后剩下sum - 1人, 那么他变成这个中的相对第几个是可以O(1)推导出来的

然后根据这个值(也就是前缀和)找到线段树对应的位置即可

代码如下:

Result  :  Accepted     Memory  :  14040 KB     Time  :  1688 ms

/*
* Author: Gatevin
* Created Time: 2015/8/15 23:28:03
* File Name: Sakura_Chiyo.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;

#define maxn 500050

struct Segment_Tree
{
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
int val[maxn << 2];
void pushUp(int rt)
{
val[rt] = val[rt << 1] + val[rt << 1 | 1];
return;
}
void build(int l, int r, int rt)
{
if(l == r)
{
val[rt] = 1;
return;
}
int mid = (l + r) >> 1;
build(lson);
build(rson);
pushUp(rt);
return;
}
void update(int l, int r, int rt, int pos, int value)
{
if(l == r)
{
val[rt] = value;
return;
}
int mid = (l + r) >> 1;
if(mid >= pos) update(lson, pos, value);
else update(rson, pos, value);
pushUp(rt);
}
int query(int l, int r, int rt, int value)//询问前缀和为k的为1(最左)位置
{
if(l == r)
return l;
int mid = (l + r) >> 1;
if(val[rt << 1] < value) return query(rson, value - val[rt << 1]);
else return query(lson, value);
}
};

Segment_Tree ST;
int cnt[maxn];
char name[maxn][12];
int nex[maxn];

void init()
{
for(int i = 1; i <= 500000; i++)
for(int j = i; j <= 500000; j += i)
cnt[j]++;
return;
}

int main()
{
int n, k;
init();
while(~scanf("%d %d", &n, &k))
{
int id = 1;
for(int i = 1; i <= n; i++)
if(cnt[i] > cnt[id])
id = i;
for(int i = 1; i <= n; i++)
scanf("%s %d", name[i], &nex[i]);
ST.build(1, n, 1);
int sum = n;
int pos = k;
for(int i = 1; i < id; i++)
{
ST.update(1, n, 1, pos, 0);
sum--;
if(nex[pos] > 0)
{
k = (k - 1 + nex[pos]) % sum;
if(k == 0) k = sum;
}
else
{
k = (k - 1 + (sum - (-nex[pos] - 1) % sum)) % sum;
if(k == 0) k = sum;
}
pos = ST.query(1, n, 1, k);
}
printf("%s %d\n", name[pos], cnt[id]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  POJ 2886 线段树