<h1>解题报告</h1>
我们对于每行建一棵线段树维护人,对于最后一列建一棵线段树。
我们要实现能插入删除的线段树,预先开点即可。
但是这样空间会爆,我们需要动态开点。
详情见代码。
#include <algorithm> #include <iostream> #include <cstring> #include <climits> #include <cstdlib> #include <cstdio> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #define LL long long const int MAXN = 300000 + 5; const int MAXM = 10000000 + 5; LL N,M,Q,M_N; inline void Read(LL &x){ x = 0;char ch = getchar(); LL flag = 1; for(;!isdigit(ch);ch = getchar()) if(ch == '-') flag = -1; for(;isdigit(ch);ch = getchar()) x = (x << 1) + (x << 3) + ch - '0'; x *= flag; } struct SegmentTree { LL val; SegmentTree lc,rc; void pushup(){ val = 0; if(lc) val += lc->val; if(rc) val += rc->val; } }pool[MAXM],*frog = pool; SegmentTree *New(){ SegmentTree *ret = ++frog; ret->lc = ret->rc = NULL; ret->val = 1; return ret; } SegmentTree *root[MAXN]; std::vector<LL> v[MAXN]; LL query(SegmentTree *v,LL l,LL r,LL x){ if(!v) return l + x - 1; if(l == r) return l; int mid = (l + r) >> 1,val = (v->lc == NULL ? 0 : v->lc->val); int h = mid - l + 1 - val; if(h >= x) return query(v->lc,l,mid,x); return query(v->rc,mid + 1,r,x-h); } void del(SegmentTree* &v,LL l,LL r,LL x){ if(!v) v = New(); if(l == r) return; int mid = (l + r) >> 1; if(x <= mid) del(v->lc,l,mid,x); else del(v->rc,mid + 1,r,x); v->pushup(); } LL del_row(LL x){ LL id = query(root[N + 1],1,M_N,x); del(root[N + 1],1,M_N,id); if(id > N) return vN+1; return id*M; } LL del_line(LL x,LL y){ LL id = query(root[x],1,M_N,y); del(root[x],1,M_N,id); if(id >= M) return vx; return (x-1)*M+id; } int main(){ Read(N);Read(M);Read(Q); M_N = std::max(N,M) + Q; for(int i = 1;i <= N + 1;i++) root[i] = NULL; while(Q--){ LL x,y; Read(x);Read(y); if(y == M){ LL id = del_row(x); v[N + 1].push_back(id); printf("%lldn",id); } else{ LL id1 = del_line(x,y),id2 = del_row(x); v[x].push_back(id2);v[N + 1].push_back(id1); printf("%lldn",id1); } } //getchar();getchar(); return 0; }