【描述】
甲苯先生在制作一个online judge,他发现做比赛的人们很关心自己的排名(显而易见),在acm赛制的比赛中,如果通过题目数量不相等,则通过题目数量多的人排名更靠前,如果通过题目数量相等,则罚时更少的人排名更高。甲苯先生想让大家帮忙设计一个程序,每次有人通过之后,就告诉他排名在他的前面有多少人。(不包括和他罚时题数都相同的同学)
【输入】
第一行输入一个整数T表示样例数。对于每一个样例:输入三个整数m, n, seed。m表示参赛总人数(编号1−m),n表示一共有n次accept(假设accept已经去重,即不存在相同人的相同题目提交)。seed表示生成数据的种子。
接下来要求同学们使用之下的函数生成数据
typedef unsigned int ui;
ui randNum(ui& seed, ui last, const ui m) {
seed = seed * 17 + last;
return seed % m + 1;
}
(last为上一次输出的结果,在没有输出结果时last=7)
要求每次生成两个数据Ria,Rib 表示Ria的人Accept了一道题目,他的罚时为Rib。(也就是说Ria的题目数量+1,罚时长度+Rib)。
要求一共生成n组数据,代表一共有n次提交
对于所有数据,保证罚时总和不超过1500000
输出
每次提交输出一行整数,表示Ria在ac后比Ria成绩高的有多少选手。
【样例输入】
1
7 3 1
【样例输出】
0
1
0
【思路】
貌似没什么好讲的,这就是一个模板,用平衡树维护一个二元组。用pair或者结构体重载运算符即可。值得一提的是,操作过程中,我们不关心节点与人的对应,对于若干个相同的节点,我们任意取出一个进行操作即可。也就是说,平衡树并不是维护每个人的信息,只是维护这样的一种局面。另外,如果没有O2,这道题有点卡常,可能需要对读入的函数进行一些丧心病狂 的修改。最初建树时注意清空。对于这种多组数据题:数组不清空,爆零两行泪 。
#include<bits/stdc++.h>
#define re register
using namespace std;
const int N=1e5+5;
typedef unsigned int ui;
int a,b,l,r,p,n,m;
inline ui red(){
ui data=0;char ch=0;
ch=getchar();
while(ch<'0' || ch>'9') ch=getchar();
while(ch>='0' && ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
return data;
}
struct node{
int num,tim;
friend inline bool operator<(const node&a,const node&b){return a.num>b.num||(a.num==b.num&&a.tim<b.tim);}
}val[N],w[N];
int ch[N][2],siz[N],pri[N],rt;
inline void pushup(const int&u){siz[u]=siz[ch[u][0]]+siz[ch[u][1]]+1;}
int merge(int x,int y){
if(!x||!y)return x|y;
if(pri[x]<pri[y])return ch[x][1]=merge(ch[x][1],y),pushup(x),x;
else return ch[y][0]=merge(x,ch[y][0]),pushup(y),y;
}
void split(int u,const node&v,int&x,int&y){
if(!u)return(void)(x=y=0);
if(val[u]<v)x=u,split(ch[u][1],v,ch[x][1],y);
else y=u,split(ch[u][0],v,x,ch[y][0]);
pushup(u);
}
ui last=7,seed;
inline ui ran(){
seed=(seed<<4)+seed+last;
return seed%m+1;
}
int build(int l,int r){
if(l>=r)return 0;
int mid=l+r>>1;siz[mid]=1;
val[mid].num=0;val[mid].tim=0;
ch[mid][0]=0;ch[mid][1]=0;
if(l==r-1)return mid;
ch[mid][0]=build(l,mid);
ch[mid][1]=build(mid+1,r);
return pushup(mid),mid;
}
int pre=0;
inline void del(const node&v){
split(rt,v,l,r);
split(r,(node){v.num,v.tim+1},p,r);pre=p;
p=merge(ch[p][0],ch[p][1]);
rt=merge(l,merge(p,r));
}
inline int add(const node&v){
split(rt,v,l,r);
int ans=siz[l];
ch[pre][0]=0;ch[pre][1]=0;
val[pre]=v;siz[pre]=1;
rt=merge(l,merge(pre,r));
return ans;
}
inline void print(ui x){
if(x>9)print(x/10);
putchar(x%10+'0');
}
int main(){
int T_T=red();
for(int re i=414;i<=827;++i)srand(rand());//不要问我这两个数有没有什么特别的含义,我不会告诉你的
for(int re i=1;i^100001;++i)pri[i]=rand();
while(T_T--){
m=red();n=red();seed=red();
memset(w,0,sizeof(w));
rt=build(1,m+1);
while(n--){l=r=p=0;
a=ran(),b=ran();del(w[a]);
++w[a].num;w[a].tim+=b;
print(last=add(w[a]));
putchar('\n');
}
}
}