列队
题目传送门
我是向其他dalao学会了这个神奇的解法,但是在某知名优秀OJ上会被卡成90分
真是令人伤心&&头大
算了
我不打算卡常了
本蒟蒻只会用Splay这种低级数据结构
像树状数组常数这么小的神奇数据结构我根本不会
分块真是令人头大
算了,这题关分块p事
考虑每次的操作我们弹出(x,y),在调整矩阵,再将(x,y)加到矩阵右下角
大概是这样
复杂度很高的地方在于矩阵的调整,每个点暴力移动实在是太蛋疼了
我们考虑用Splay维护
对于每一行的前n-1个数建立Splay,对最后一列建立Splay,点在Splay上的移动的复杂度是令人愉悦的
这些Splay和平常的Splay不太一样
他们需要支持以下操作
- rotate&&splay(似乎是废话)
- 类似于vector的push_back
- 分裂节点(题目中节点数过多,内存问题需要通过大量节点的合并来解决)
- 弹出Splay中第k个数
听起来真TM简单
写起来真TM蛋疼
rotate
#define dir(x) (son[fa[x]][1]==x)
inline void rotate(long long root,long long d)
{
long long temp=son[root][d^1];
son[root][d^1]=son[temp][d];
if(son[root][d^1])fa[son[root][d^1]]=root;
fa[temp]=fa[root];
if(fa[root])son[fa[root]][dir(root)]=temp;
fa[root]=temp,son[temp][d]=root;
push_up(root),push_up(temp);
}
这种路人皆知的操作为什么我还要粘
Splay
inline void splay(long long root,long long goal)
{
while(fa[root]^goal)
{
if(fa[fa[root]]^goal&&dir(root)==dir(fa[root]))
rotate(fa[fa[root]],dir(root)^1);
rotate(fa[root],dir(root)^1);
}
push_up(root);
if(!goal)Root=root;
}
我怎么把splay也给粘上来了
new_node(制造新节点)
inline long long new_node(long long left,long long right)
{
long long temp=++Splay_size;
l[temp]=left,r[temp]=right;
size[temp]=r[temp]-l[temp]+1;
return temp;
}
注意left,right表示这个节点所代表的区间(节点信息为了省内存而合并)
Split
神奇的分裂节点术来了
inline long long split(long long x,long long k)//将节点x的前k个信息保留在x中,剩余的作为新节点返回
{
k+=l[x];
long long temp=new_node(k,r[x]);
r[x]=k-1;
if(!son[x][1])//维护中序遍历,让新节点在x的右侧一个的位置
son[x][1]=temp,fa[temp]=x;
else
{
long long root=son[x][1];
while(son[root][0])root=son[root][0];
son[root][0]=temp,fa[temp]=root;//找到x右侧第一个点的位置
while(root^x)push_up(root),root=fa[root];
}
splay(temp,0);//每次拉到根维护信息
return temp;
}
Pop_kth
更神奇的弹出第k个节点来了
inline long long pop_kth(long long k)
{
long long root=Root;
while(true)
{
if(k<=size[son[root][0]])root=son[root][0];
else
{
k-=size[son[root][0]];
if(k<=r[root]-l[root]+1)
{
if(k^(r[root]-l[root]+1))split(root,k);//如果不是最右面的信息,就要把右面的信息split掉
if(k^1)root=split(root,k-1);//如果不是最左边的信息,就要把左边的信息split掉
break;
}
else
k-=r[root]-l[root]+1,root=son[root][1];
}
}
splay(root,0);
fa[son[root][0]]=fa[son[root][1]]=0;//删除根,一会将根弹出
if(!son[root][0])Root=son[root][1];
else
{
long long temp=son[root][0];
while(son[temp][1])temp=son[temp][1];
splay(temp,0);
fa[son[root][1]]=temp,son[temp][1]=son[root][1],Root=temp;
push_up(temp);
}
return l[root];
}
Push_back
inline void push_back(long long x)
{
long long root=Root,temp=new_node(x,x);
if(!Root)
{
Root=temp;
return;
}
while(son[root][1])root=son[root][1];
splay(root,0);
son[root][1]=temp;
fa[temp]=root;
push_up(root);
}
似乎没了
下面是整体代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#define MAXN 2000010
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(long long &x)
{
long long s=0,w=1;
char c=nc();
while(!isdigit(c)){if(c=='-')w=-1;c=nc();}
while(isdigit(c)){s=(s<<3)+(s<<1)+c-'0';c=nc();}
x=s*w;
}
inline void write(long long x)
{
if(x<0)x=-x,putchar('-');
if(x>9)write(x/10);
putchar('0'+x%10);
}
long long size[MAXN],l[MAXN],r[MAXN],fa[MAXN],son[MAXN][2],Splay_size;
struct Splay_Tree
{
long long Root;
#define push_up(root) (size[root]=size[son[root][0]]+size[son[root][1]]+r[root]-l[root]+1)
#define dir(x) (son[fa[x]][1]==x)
inline void rotate(long long root,long long d)
{
long long temp=son[root][d^1];
son[root][d^1]=son[temp][d];
if(son[root][d^1])fa[son[root][d^1]]=root;
fa[temp]=fa[root];
if(fa[root])son[fa[root]][dir(root)]=temp;
fa[root]=temp,son[temp][d]=root;
push_up(root),push_up(temp);
}
inline void splay(long long root,long long goal)
{
while(fa[root]^goal)
{
if(fa[fa[root]]^goal&&dir(root)==dir(fa[root]))
rotate(fa[fa[root]],dir(root)^1);
rotate(fa[root],dir(root)^1);
}
push_up(root);
if(!goal)Root=root;
}
inline long long new_node(long long left,long long right)
{
long long temp=++Splay_size;
l[temp]=left,r[temp]=right;
size[temp]=r[temp]-l[temp]+1;
return temp;
}
inline long long split(long long x,long long k)
{
k+=l[x];
long long temp=new_node(k,r[x]);
r[x]=k-1;
if(!son[x][1])
son[x][1]=temp,fa[temp]=x;
else
{
long long root=son[x][1];
while(son[root][0])root=son[root][0];
son[root][0]=temp,fa[temp]=root;
while(root^x)push_up(root),root=fa[root];
}
splay(temp,0);
return temp;
}
inline long long pop_kth(long long k)
{
long long root=Root;
while(true)
{
if(k<=size[son[root][0]])root=son[root][0];
else
{
k-=size[son[root][0]];
if(k<=r[root]-l[root]+1)
{
if(k^(r[root]-l[root]+1))split(root,k);
if(k^1)root=split(root,k-1);
break;
}
else
k-=r[root]-l[root]+1,root=son[root][1];
}
}
splay(root,0);
fa[son[root][0]]=fa[son[root][1]]=0;
if(!son[root][0])Root=son[root][1];
else
{
long long temp=son[root][0];
while(son[temp][1])temp=son[temp][1];
splay(temp,0);
fa[son[root][1]]=temp,son[temp][1]=son[root][1],Root=temp;
push_up(temp);
}
return l[root];
}
inline void push_back(long long x)
{
long long root=Root,temp=new_node(x,x);
if(!Root)
{
Root=temp;
return;
}
while(son[root][1])root=son[root][1];
splay(root,0);
son[root][1]=temp;
fa[temp]=root;
push_up(root);
}
inline void build(long long left,long long right)
{
Root=new_node(left,right);
}
#undef push_up
#undef dir
}Splay[MAXN];
long long n,m,q,x,y,p;
int main()
{
read(n),read(m),read(q);
for(register long long i=1;i<=n;i++)
Splay[i].build((i-1)*m+1,i*m-1);
Splay[0].build(m,m);
for(register long long i=2;i<=n;i++)
Splay[0].push_back(i*m);
while(q--)
{
read(x),read(y);
Splay[x].push_back(Splay[0].pop_kth(x));
p=Splay[x].pop_kth(y);
write(p),putchar(10);
Splay[0].push_back(p);
}
}