洛谷P3960 列队 splay
题目链接
https://www.luogu.org/problemnew/show/P3960
题解
观察到向左看齐和向前看齐真正影响的是当前行第y列和当前行的最后一个人,于是每行除最后一个建一个splay,最后一列单独建一个splay。
对于每次操作,删除第x个splay树的第y个,将最后一列的第x个(即第x行最后一列)加入第x个splay树的末尾,再将删除的那个节点加入最后一列的splay树的末尾。
代码
// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=3e6+10;
typedef long long ll;
int n,m,q;
int fa[maxn],ch[maxn][2],cnt;
ll L[maxn],R[maxn],size[maxn];
int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
struct Splay{
int root;
int newnode(ll l,ll r){
++cnt;
fa[cnt]=ch[cnt][0]=ch[cnt][1]=0;
size[cnt]=r-l+1;
R[cnt]=r;L[cnt]=l;
return cnt;
}
void build(ll l,ll r){
root=newnode(l,r);
}
void update(int x){ size[x]=size[ch[x][0]]+size[ch[x][1]]+R[x]-L[x]+1;}
void rotate(int x){
int f1=fa[x],f2=fa[f1];
int s1=ch[f1][1]==x,s2=ch[f2][1]==f1;
ch[f2][s2]=x;
fa[x]=f2;
ch[f1][s1]=ch[x][s1^1];
fa[ch[x][s1^1]]=f1;
ch[x][s1^1]=f1;
fa[f1]=x;
update(f1);update(x);
}
void splay(int x){
while(fa[x]!=0){
int f1=fa[x],f2=fa[f1];
if(f2!=0)
(ch[f1][1]==x)^(ch[f2][1]==f1)?rotate(x):rotate(f1);
rotate(x);
}
root=x;
}
int splitnode(int x,ll k){
k+=L[x];
int u=newnode(k,R[x]);
R[x]=k-1;
if(ch[x][1]==0){
ch[x][1]=u;
fa[u]=x;
}
else{
int now=ch[x][1];
while(ch[now][0])now=ch[now][0];
ch[now][0]=u;
fa[u]=now;
while(now!=x)update(now),now=fa[now];
}
splay(u);
return u;
}
ll kth(ll k){
int u=root;
while(7){
int x=ch[u][0];
if(size[x]>=k)u=ch[u][0];
else{
k-=size[x];
if(k<=R[u]-L[u]+1){
if(k!=R[u]-L[u]+1)splitnode(u,k);
if(k!=1)u=splitnode(u,k-1);
break;
}
else{
k-=R[u]-L[u]+1;
u=ch[u][1];
}
}
}
splay(u);
fa[ch[u][0]]=fa[ch[u][1]]=0;
if(!ch[u][0]) root=ch[u][1];
else{
int x=ch[u][0];
while(ch[x][1])x=ch[x][1];
splay(x);
ch[x][1]=ch[u][1];
root=fa[ch[x][1]]=x;
update(x);
}
return L[u];
}
void insert(ll x){
int y=newnode(x,x);
if(!root) root=y;
else{
int u=root;
while(ch[u][1])u=ch[u][1];
splay(u);
ch[u][1]=y;
fa[y]=u;
update(u);
}
}
}T[maxn];
int main(){
n=read();m=read();q=read();
for(ll i=1;i<=n;i++)T[i].build((i-1)*m+1,i*m-1);
T[0].build(m,m);
for(ll i=2;i<=n;i++)T[0].insert(i*m);
while(q--){
int x=read(),y=read();
T[x].insert(T[0].kth(x));
ll ans=T[x].kth(y);
printf("%lld\n",ans);
T[0].insert(ans);
}
}