problem
甲苯先生在制作一个 online judge。
OJ 有 n n n 个人,给出 m m m 次操作。每次操作给定两个数 x , y x,y x,y,表示第 x x x 个人 AC 数 + 1 +1 +1,罚时 + y +y +y。每次操作后要输出有多少人排在 x x x 前面。
排序的方式是:以 AC 数从大到小为第一关键字,以罚时从小到大为第二关键字。不包括 AC 数和罚时都和 x x x 相等的。
数据范围: n ≤ 1 0 5 n\le 10^5 n≤105, m ≤ 1 0 6 m\le 10^6 m≤106。
solution
这道题其实蛮简单的。
方法 1 1 1、Splay:
我们用 pair 来存储每个人的 AC 数和罚时,直接用 Splay 维护即可。
要注意的是,根据 pair 的特性我们需要把 second(即罚时)取相反数存储。
大概可以拿 80 80 80 分,卡卡常应该能过。
方法 1 1 1、Segment Tree & \& & BIT:
用一个树状数组维护 AC 数。再开 m m m 颗权值线段树,第 i i i 颗线段树维护的是 AC 数为 i i i 的人的罚时。
然后直接在树状数组上查 AC 数严格大于 x x x 的数量,然后在权值线段树上处理罚时比 x x x 小的。修改也比较简单。
要注意的是空间问题,要动态开点。
code
Splay:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 2000005
#define inf 1<<30
using namespace std;
typedef unsigned int uint;
typedef pair<int,int> Pair;
int n,m,Ac[N],Time[N];uint seed,last=7;
uint Rand(uint &seed,uint last){
seed=seed*17+last;
return seed%n+1;
}
namespace SPLAY{
Pair val[N];
int root,tot,cnt[N],fa[N],son[N][2],Size[N];
int Get(int x) {return son[fa[x]][1]==x;}
void update(int x) {Size[x]=Size[son[x][0]]+Size[son[x][1]]+cnt[x];}
void Rotate(int x){
int y=fa[x],z=fa[y];
int k=Get(x),l=son[x][k^1];
fa[l]=y,son[y][k]=l;
fa[x]=z,son[z][Get(y)]=x;
fa[y]=x,son[x][k^1]=y;
update(y),update(x);
}
void Splay(int x,int goal=0){
while(fa[x]!=goal){
int y=fa[x],z=fa[y];
if(z!=goal) Rotate(Get(x)==Get(y)?y:x);
Rotate(x);
}
if(!goal) root=x;
}
void Insert(Pair x){
int now=root,par=0;
while(now&&val[now]!=x) par=now,now=son[now][val[now]<x];
if(now) cnt[now]++;
else{
now=++tot;
if(par) son[par][val[par]<x]=now;
son[now][0]=son[now][1]=0,Size[now]=cnt[now]=1;
fa[now]=par,val[now]=x;
}
Splay(now);
}
void find(Pair x){
int now=root;
while(x!=val[now]&&son[now][val[now]<x])
now=son[now][val[now]<x];
Splay(now);
}
int Pre(Pair x){
find(x);
if(val[root]<x) return root;
int now=son[root][0];
while(son[now][1]) now=son[now][1];
return now;
}
int Suf(Pair x){
find(x);
if(val[root]>x) return root;
int now=son[root][1];
while(son[now][0]) now=son[now][0];
return now;
}
void Delete(Pair x){
int Last=Pre(x);
int Next=Suf(x);
Splay(Last),Splay(Next,Last);
int now=son[Next][0];
if(cnt[now]>1) cnt[now]--,Splay(now);
else son[Next][0]=0;
}
}
using namespace SPLAY;
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d%u",&n,&m,&seed),root=tot=0;
Insert(make_pair(inf,-inf)),Insert(make_pair(-inf,inf));
memset(Ac,0,sizeof(Ac)),memset(Time,0,sizeof(Time));
while(m--){
int x=Rand(seed,last),y=Rand(seed,last);
if(Ac[x]) Delete(make_pair(Ac[x],-Time[x]));
++Ac[x],Time[x]+=y,Insert(make_pair(Ac[x],-Time[x]));
last=Size[son[root][1]]-1,printf("%d\n",last);
}
}
return 0;
}
Segment Tree:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define lowbit(x) (x&(-x))
using namespace std;
typedef unsigned int uint;
const int N=1000005,lim=1500000;
uint seed,last=7;
int n,m,Ac[N],Time[N];
uint Rand(uint &seed,uint last){
seed=seed*17+last;
return seed%n+1;
}
namespace BIT{
int bit[N];
void Clear(){
memset(bit,0,sizeof(bit));
}
void add(int x,int val){
for(;x<N;x+=lowbit(x)) bit[x]+=val;
}
int ask(int x,int ans=0){
for(;x;x-=lowbit(x)) ans+=bit[x];
return ans;
}
};
using namespace BIT;
namespace SEG{
struct node{
int lc,rc,num;
}Seg[N*40];
int tot,root[N];
void init(){
tot=0;
memset(root,0,sizeof(root));
}
#define mid ((l+r)>>1)
void Modify(int &root,int l,int r,int pos,int v){
if(!root){
root=++tot;
Seg[root].lc=Seg[root].rc=Seg[root].num=0;
}
if(l==r) {Seg[root].num+=v;return;}
if(pos<=mid) Modify(Seg[root].lc,l,mid,pos,v);
else Modify(Seg[root].rc,mid+1,r,pos,v);
Seg[root].num=Seg[Seg[root].lc].num+Seg[Seg[root].rc].num;
}
int Query(int &root,int l,int r,int x,int y){
if(!root) return 0;
if(l>=x&&r<=y) return Seg[root].num;
if(y<=mid) return Query(Seg[root].lc,l,mid,x,y);
if(x> mid) return Query(Seg[root].rc,mid+1,r,x,y);
return Query(Seg[root].lc,l,mid,x,y)+Query(Seg[root].rc,mid+1,r,x,y);
}
}
using namespace SEG;
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d%u",&n,&m,&seed),Clear(),init();
memset(Ac,0,sizeof(Ac)),memset(Time,0,sizeof(Time));
for(int i=1;i<=n;++i) Ac[i]=Time[i]=1;
add(1,n),Modify(root[1],1,lim,1,n);
while(m--){
int x=Rand(seed,last),y=Rand(seed,last);
add(Ac[x],-1),Modify(root[Ac[x]],1,lim,Time[x],-1);
Ac[x]++,Time[x]+=y;
add(Ac[x],1),Modify(root[Ac[x]],1,lim,Time[x],1);
last=n-ask(Ac[x]),last+=Query(root[Ac[x]],1,lim,1,Time[x]-1);
printf("%d\n",last);
}
}
return 0;
}