题目链接如下:
2886 -- Who Gets the Most Candies?
大意就是说,第i个人出圈,数到下一个val[i]的人就要出圈,同时第i个出圈的人获得i的质因数的大小的candies,问第那个获得最多的人的名字和candies是多少。
这里用线段树维护一个区间个数,然后做点修改,我们每次要从删除的点获取下一次要删除点的次序如何,需要维护左右的人的个数,这可以通过次序和总数算出来,然后再由删除的位置来更新下一个要删除的点的次序是在哪,直到删除到最大的公因子的那个数字。
代码如下所示:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<vector>
#include<algorithm>
#include<cstring>
#include<set>
#include<map>
#include<queue>
#include<string>
#include<cmath>
#include<climits>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int MAXN=500050;
char name[MAXN][11];
int val[MAXN];
int f[MAXN];
int sum[MAXN<<2];
void make_table(int n){
for (int i = 1; i < n; ++i) {
f[i]=1;
}
for (int i = 2; i < n; ++i) {
for (int j = i; j < n; j+=i) {
f[j]++;
}
}
}
int get_order(int n){
int k=1;
for (int i = 2; i <= n; ++i) {
if (f[k]<f[i]){
k=i;
}
}
return k;
}
void push_up(int rt){
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void build(int l,int r,int rt){
if (l==r){
sum[rt]=1;
return;
}
int mid=(l+r)>>1;
build(lson);
build(rson);
push_up(rt);
}
int update(int pos,int l,int r,int rt){
if (l==r){
sum[rt]=0;
return l;
}
int mid=(l+r)>>1;
int res;
if (pos<=sum[rt<<1]){
res=update(pos,lson);
} else{
res=update(pos-sum[rt<<1],rson);
}
push_up(rt);
return res;
}
int main(){
int n,k;
make_table(MAXN);
while (~scanf("%d %d",&n,&k)){
for (int i = 1; i <= n; ++i) {
scanf("%s %d",name[i],&val[i]);
// cout<<name[i]<<","<<val[i]<<endl;
}
build(1,n,1);
int order=get_order(n);
int pos=0;
int num=k;
int ln,rn;
int total=n;
for (int i = 1; i <= order; ++i) {
pos= update(num,1,n,1);
if (i==order) break;
total--;
ln=num-1;
rn=total-num+1;
int v=val[pos];
if (v>0){
v%=total;
if (!v) v=total;
if (v<=rn){
num=ln+v;
} else{
num=v-rn;
}
} else{
v=-v;
v%=total;
if (!v)v=total;
if (v<=ln){
num=ln-v+1;
} else{
num=total-v+ln+1;
}
}
}
printf("%s %d\n",name[pos],f[order]);
}
return 0;
}