@ysner
2018-10-25T13:10:41.000000Z
字数 1617
阅读 2392
线段树 主席树 vector
无人不知,无人不晓
想想如何简化题目中的操作。
一个人到,暴力模拟的复杂度是。
考虑节省掉移动整行整列的复杂度。
实际上,不如让一个人移走后留下的位置空着。
这样一行最多只有,是可以维护的。
于是用棵线段树维护一下每一行中,区间内有多少个空位置。
这样就可以查出一行的第个在哪里。
当然,如果每行线段树都开全,空间复杂度开不下。
所以需要动态开点。
注意到只有行和第列有可能新加入数。
可以用存一下,每行新加入了什么数(第列不包含在内)。
还有一个存第列新加入的数。
另外,删掉中的数也是级别的。所以每行的线段树也要维护中的空位置。
这么以来,操作就转化为在数据结构的基础上模拟了。
#include<iostream>#include<cmath>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<vector>#define ll long long#define re register#define il inline#define pb push_back#define fp(i,a,b) for(re int i=a;i<=b;++i)#define fq(i,a,b) for(re int i=a;i>=b;--i)using namespace std;const int N=3e5+100;int n,m,q,t[N*100],tot,rt[N*100],tim,ls[N*100],rs[N*100];vector<ll>V[N];il ll gi(){re ll x=0,t=1;re char ch=getchar();while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();if(ch=='-') t=-1,ch=getchar();while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();return x*t;}il void Inherit(re int &x){rt[++tim]=rt[x];t[tim]=t[x];ls[tim]=ls[x];rs[tim]=rs[x];x=tim;}il int Query(re int &x,re int l,re int r,re int k){Inherit(x);if(l==r) {t[x]=1;return l;}re int mid=l+r>>1,sz=mid-l+1-t[ls[x]],ans;if(k<=sz) ans=Query(ls[x],l,mid,k);else ans=Query(rs[x],mid+1,r,k-sz);t[x]=t[ls[x]]+t[rs[x]];return ans;}il ll find(re int i,re int k){re ll ans=Query(rt[i],1,tot,k),l=(i<=n?m-1:n);if(ans<=l) return i<=n?1ll*(i-1)*m+ans:ans*m;else return V[i][ans-l-1];}int main(){n=gi();m=gi();q=gi();tot=max(n,m)+q;fp(i,1,n+1) rt[i]=++tim;fp(i,1,q){re int x=gi(),y=gi();re ll p1,p2;if(y^m){p1=find(x,y);V[n+1].pb(p1);//a new member on lie mp2=find(n+1,x);V[x].pb(p2);//new one ->the n_th line}else p1=find(n+1,x),V[n+1].pb(p1);printf("%lld\n",p1);}return 0;}
