splay什么的太简单啦,我不会写
开n个线段树暴力地维护每一行前m-1个数据的信息,叶子结点存储该点的值,其他节点存子树中点的个数
再开一个线段树维护最后一列数据的信息
对于一组输入
如果
那就是在最后一个线段树里面取出第x个放到最后
如果 那就是在第x个线段树取出第y个放到最后一个线段树末尾,再把最后一个线段树第x位加到第x个线段树末尾。
但是n+1个线段树开满M飞飞怎么办
动态开点
那些用不到的暂时别开,等要用的时候再开。
代码不长,注意细节就行。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 300010;
int n , m , q , z;
int cnt;
int root[maxn] , num[maxn];
bool f;
struct tree{
int ls , rs;
int size;
ll id;
}tr[maxn * 30];
int read(){
int sum = 0;bool flag = true;char c = getchar();
while(c<'0'||c>'9') {if(c=='-') flag = false; c = getchar();}
while(c>='0'&&c<='9') sum = sum * 10 + c - 48 , c = getchar();
if(flag) return sum;
else return -sum;
}
ll find(int &root , int l , int r , int x){
if(!root) root = ++cnt , tr[root].size = max( 0 , min( z , r ) - l + 1);
tr[root].size -- ;
if( l == r ){
if( l <= z ){f = true;return l;}
else return tr[root].id;
}
int mid = (l + r ) / 2 , ls;
if(!tr[root].ls) ls = max( 0 , min ( z , mid ) - l + 1);
else ls = tr[tr[root].ls].size;
if( ls >= x ) return find( tr[root].ls , l , mid , x);
else return find( tr[root].rs , mid + 1 , r ,x - ls);
}
void insert(int &root , int l , int r , int p , long long x){
if(!root) root = ++cnt , tr[root].size = max( 0 , min( z , r ) - l + 1);
tr[root].size ++ ;
if(l == r){tr[root].id = x;return;}
int mid = ( l + r ) / 2;
if( mid >= p ) insert( tr[root].ls , l , mid , p , x );
else insert( tr[root].rs , mid + 1, r , p , x );
return;
}
void solve(){
for(int i = 1;i <= q;++i){
int x = read() , y = read();
if( y < m ){//该点不在最后一列
z = m - 1;
ll id1 = find( root[x] , 1 , m - 1 + q , y );//找到该点
if(f) id1 = (ll)( x - 1 ) * m + id1 , f = false;
printf("%lld\n",id1);
z = n;
ll id2 = find( root[0] , 1 , n + q , x );//找到最后一列插进来的那个点。
if(f) id2 =(ll) id2 * m , f = false;
num[x]++;num[0]++;
z = m - 1;insert( root[x] , 1 , m - 1 + q , num[x] , id2);
z = n;insert( root[0] , 1 , n + q , num[0] , id1);
}
else{
z = n;
ll id1 = find( root[0] , 1 , n + q , x );
if(f) id1 =(ll) id1 * m , f = false;
printf("%lld\n",id1);
num[0]++;
insert(root[0] , 1 , n + q , num[0] , id1);
}
}
return;
}
void first(){
for(int i = 1;i <= n;++i){//每一行
root[i] = ++cnt;
tr[cnt].size = num[i] = m - 1;
}
root[0] = ++cnt;tr[cnt].size = num[0] = n;//维护最后一列
return;
}
int main(){
n = read();m = read();q = read();
first();
solve();
return 0;
}