最后の汤圆
Time Limit: 1000MS Memory Limit: 65536KB
Problem Description
又到了汤圆星球一年一度的汤圆节了,恰好这一天是地球的元宵节,出于这个巧合,两球之间早在数百年前就建立起了长久稳固的友好外交关系。
良好的外交需要物质的支持,此次汤圆星球外交使者向地球朋友们进贡了上等的汤圆。汤圆星球的汤圆使者送来的n(1<=n <= 500000)个汤圆中,每个汤圆都有一个口感指数ti(0 < ti<=10^8),而且汤圆使者还为地球朋友们提供了一种新(qi) 颖(pa)的汤圆吃法,据说可以使口感倍增。
这种尽(sang)善(xin)尽(bing)美(kuang)的吃法是:先将n个汤圆排成一个圈儿,并且按照顺时针方向给汤圆编号为1~n, 然后从编号为k(1<=k<=n)的汤圆开始吃,每吃掉一个汤圆后,会获得它的口感指数,这个口感指数决定了下一个即将被吃掉的汤圆:
假设这个刚被吃掉的汤圆的口感指数是A,那么从刚被吃掉的这个汤圆开始,顺时针数第A个汤圆就是下一个即将被吃掉的汤圆。
现在按照汤圆编号1~n的顺序给定每个汤圆的口感指数ti,求最后一个被吃掉的汤圆的编号。
Input
多组输入,数据范围见题目描述。
对于每组输入第一行有两个整数n和k,分别代表汤圆的数量和第一个被吃的汤圆。
第二行有n个以空格间隔的整数t1 t2 t3 … tn,第i个整数ti代表第i个汤圆的口感指数。
Output
对于每组数据输出一个整数,表示最后一个被吃掉的汤圆的编号。
Example Input
4 2
1 3 5 7
4 3
2 3 3 3
Example Output
4
1
思路:
假期回来的比赛防AK的一道题,完全想不到这种思路,听东庆巨巨讲解了一波才懂得。我们需要把这n个汤圆的下标构成一个线段树。结构体成员定义一个pos,用来判断对应下标的位置在树的左边还是右边。pos是取右孩子的值。这样查找的时候就可以判断如果大于左孩子就去右孩子寻找下标值。如果要删除第k个汤圆(找第k个汤圆原来的下标),我们就将(原来的下标-n)的下标都减1,这样就出现了重复的下标,重复的下标中右边的是不需要的(已经被删除了)。我们需要查找下一个我们要删除下标(原来的下标),具体还是看代码吧。
#include<bits/stdc++.h>
using namespace std;
struct node
{
int pos, lazy;
};
node tree[4 * 500000];
int a[500055];
#define MID int mid = (l + r) / 2
#define lson root<<1
#define rson root<<1|1
node merge_(node x, node y)
{
node t;
t.lazy = 0;
t.pos = y.pos;//等于右孩子的值
return t;
}
void build(int root, int l, int r)//初始化以下标建线段树
{
tree[root].lazy = 0;
if(l == r)
{
tree[root].pos = r;
return ;
}
MID;
build(lson, l, mid);
build(rson, mid + 1, r);
tree[root] = merge_(tree[lson], tree[rson]);
}
void pushdown(int root, int l, int r)//向下更新
{
if(tree[root].lazy)
{
tree[lson].lazy += tree[root].lazy;
tree[rson].lazy += tree[root].lazy;
tree[lson].pos += tree[root].lazy;//pos是右孩子的值,也就是加上lazy的值就可以了
tree[rson].pos += tree[root].lazy;
tree[root].lazy = 0;
}
}
void updata(int root, int l, int r,int ul, int ur, int v)
{
if(ul <= l && r <= ur)//在区间范围内
{
tree[root].lazy += v;//lazy的值-1
tree[root].pos += v;//pos的值-1
return ;
}
pushdown(root, l, r);
MID;
if(mid >= ul) updata(lson, l, mid, ul, ur, v);
if(mid < ur) updata(rson, mid + 1, r, ul, ur, v);
tree[root] = merge_(tree[lson], tree[rson]);
}
int Search(int root, int l, int r, int po)//查找当前下标po,对应的原来下标是几
{
if(l == r)
{
return l;
}
pushdown(root, l, r);
MID;
int red;
if(po <= tree[lson].pos) red = Search(lson, l, mid, po);
else red = Search(rson, mid + 1, r, po);
return red;
}
int main()
{
int n, k, v;
while(~scanf("%d %d", &n, &k))
{
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
}
build(1, 1, n);
int t = n;
while(t--)
{
v = Search(1, 1, n, k);//要删除第几个数对应的原来的下标
if(!t)
{
printf("%d\n", v);
break;
}
updata(1, 1, n, v, n, -1);
k = (a[v] + k - 1 - 1) % t + 1;//要删除第几个数
}
}
return 0;
}