背景:
Sir.C
₇
H
₈
\text{Sir.}\text{C}₇\text{H}₈
Sir.C₇H₈系列的数据结构的题。
题目传送门:
https://www.luogu.org/problemnew/show/P5338
题意:
求动态的两个关键字
x
,
y
x,y
x,y(
A
C
AC
AC数,罚时)的排名。
思路:
显然用
splay
\text{splay}
splay。
因为
x
≤
1.5
∗
1
0
6
x≤1.5*10^6
x≤1.5∗106,因此取一个
z
=
1
0
7
x
−
y
z=10^7x-y
z=107x−y(罚时越少越好,因此是负贡献)即可,就可以做到
s
p
l
a
y
splay
splay只维护一个关键字
z
z
z了。
注意一些细节。
如
s
e
e
d
seed
seed的类型是
unsigned int
\text{unsigned int}
unsigned int,坑了我好久。
再如,你的
splay
\text{splay}
splay是
左
儿
子
<
根
<
右
儿
子
左儿子<根<右儿子
左儿子<根<右儿子,因此你在统计答案时要删除跟自己
z
z
z相同的人的影响。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define UI unsigned int
using namespace std;
UI seed;
int n,m,last=7;
LL a[2000010];
struct node{LL d;int fa,c,n,son[2];} tr[2000010];
int root,len;
void ups(int x)
{
tr[x].c=tr[tr[x].son[0]].c+tr[tr[x].son[1]].c+tr[x].n;
}
void add(LL d,int fa)
{
tr[++len]=(node){d,fa,1,1,0};
}
void rot(int x,int w)
{
int y=tr[x].fa,yy=tr[y].fa;
tr[y].son[1^w]=tr[x].son[w];
if(tr[x].son[w]) tr[tr[x].son[w]].fa=y;
tr[yy].son[tr[yy].son[0]==y?0:1]=x;
tr[x].fa=yy,tr[x].son[w]=y,tr[y].fa=x;
ups(y),ups(x);
}
void splay(int x,int rt)
{
while(tr[x].fa!=rt)
{
int y=tr[x].fa,yy=tr[y].fa;
if(yy==rt)
{
rot(x,tr[y].son[0]==x?1:0);
continue;
}
if(tr[yy].son[0]==y)
{
if(tr[y].son[0]==x) rot(y,1),rot(x,1); else rot(x,0),rot(x,1);
continue;
}
if(tr[y].son[1]==x) rot(y,0),rot(x,0); else rot(x,1),rot(x,0);
}
if(!rt) root=x;
}
int findip(int x,LL d)
{
if(d==tr[x].d) return x;
if(d<tr[x].d)
return tr[x].son[0]?findip(tr[x].son[0],d):x;
else
return tr[x].son[1]?findip(tr[x].son[1],d):x;
}
void ins(LL d)
{
if(!root)
{
add(d,0);
root=1;
return;
}
int u=findip(root,d);
if(tr[u].d==d)
{
tr[u].n++;
ups(u);
splay(u,0);
return;
}
add(d,u);
tr[u].son[d<tr[u].d?0:1]=len;
ups(u);
splay(len,0);
}
void del(LL d)
{
int u=findip(root,d);
splay(u,0);
if(tr[u].n>1)
{
tr[u].n--;
ups(u);
return;
}
if(!tr[u].son[0]&&!tr[u].son[1])
{
root=len=0;
return;
}
if(!tr[u].son[0]&&tr[u].son[1])
{
root=tr[u].son[1];
tr[tr[u].son[1]].fa=0;
return;
}
if(tr[u].son[0]&&!tr[u].son[1])
{
root=tr[u].son[0];
tr[tr[u].son[0]].fa=0;
return;
}
int o=tr[u].son[0];
while(tr[o].son[1]) o=tr[o].son[1];
splay(o,u);
tr[o].son[1]=tr[u].son[1];
tr[tr[o].son[1]].fa=o;
root=o;
tr[o].fa=0;
ups(o);
}
int findrank(LL d)
{
int u=findip(root,d);
splay(u,0);
return tr[tr[u].son[0]].c+1;
}
int randnum()
{
seed=seed*17+last;
return seed%n+1;
}
int main()
{
int T,x,y;
scanf("%d",&T);
while(T--)
{
scanf("%d %d %u",&n,&m,&seed);
root=len=0;
for(int i=1;i<=n;i++)
tr[i]=(node){0,0,0,0,0,0};
for(int i=1;i<=n;i++)
{
a[i]=0;
ins(0);
}
for(int i=1;i<=m;i++)
{
x=randnum(),y=randnum();
del(a[x]);
a[x]+=10000000-y;
ins(a[x]);
last=(n-findrank(a[x])-(tr[findip(root,a[x])].n-1));
printf("%d\n",last);
}
}
}