NOIPD2T3列队题解

splay什么的太简单啦,我不会写
开n个线段树暴力地维护每一行前m-1个数据的信息,叶子结点存储该点的值,其他节点存子树中点的个数
再开一个线段树维护最后一列数据的信息

对于一组输入 ( x , y )
如果 y = m 那就是在最后一个线段树里面取出第x个放到最后

如果 y < m 那就是在第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;
} 

猜你喜欢

转载自blog.csdn.net/a1035719430/article/details/80022590