题目描述
题目
考试有想过每行建一棵树,但是发现空间会爆,就去打模拟了。。。
然而,正解就是每行建一棵树(最后一列单独建一棵),只不过是把插入操作改成删除操作就好了。
因为每次离队影响到的只会是人所在的行和列(如果是最后一列的离队只会影响行)。
对于后面插进来的元素用vector存一下就好
懒得去算要开多大的空间,并且最近玩数据结构玩得有点疯,就打了个指针版的线段树(并没有和打平衡树一样查错查半天,有点开心)
下面是代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#define ll long long
using namespace std;
const int N=300010;
ll n,m,q,mn;
struct node
{
node* ch[2];ll s;
node(){ch[0]=ch[1]=NULL;s=1;}
void maintain()
{
s=0;
if(ch[0] != NULL) s+=ch[0]->s;
if(ch[1] != NULL) s+=ch[1]->s;
}
};
node* rt[N];
vector<ll> g[N];
ll query(node* o,ll l,ll r,ll x)
{
if(o == NULL) return l+x-1;
if(l == r) return l;
int mid=(l+r)>>1,ss=(o->ch[0]==NULL?0:o->ch[0]->s);
int h=mid-l+1-ss;
if(h >= x) return query(o->ch[0],l,mid,x);
return query(o->ch[1],mid+1,r,x-h);
}
void del(node* &o,ll l,ll r,ll x)
{
if(o == NULL) o=new node();
if(l == r) return ;
int mid=(l+r)>>1;
if(x <= mid) del(o->ch[0],l,mid,x);
else del(o->ch[1],mid+1,r,x);
o->maintain();
}
ll del_row(ll x)
{
ll idx=query(rt[n+1],1,mn,x);
del(rt[n+1],1,mn,idx);
if(idx > n) return g[n+1][idx-n-1];
return idx*m;
}
ll del_line(ll x,ll y)
{
ll idx=query(rt[x],1,mn,y);
del(rt[x],1,mn,idx);
if(idx >= m) return g[x][idx-m];
return (x-1)*m+idx;
}
int read()
{
int out=0,f=1;char c=getchar();
while(c < '0' || c > '9') {if(c == '-') f=-1;c=getchar();}
while(c >= '0' && c <= '9' )
{out=(out<<1)+(out<<3)+c-'0';c=getchar();}
return out*f;
}
void solve()
{
n=read();m=read();q=read();mn=max(n,m)+q;
for(int i=1;i<=n+1;i++) rt[i]=NULL;
for(int i=1;i<=q;i++)
{
ll x=read(),y=read();
if(y == m)
{
ll id=del_row(x);
g[n+1].push_back(id);
printf("%lld
",id);
}
else
{
ll id1=del_line(x,y),id2=del_row(x);
g[x].push_back(id2);g[n+1].push_back(id1);
printf("%lld
",id1);
}
}
}
int main()
{
solve();
return 0;
}