[NOIP 2017]列队
题意:维护一个矩阵的左对齐和上对齐,并输出结果。
思路:
正解似乎是树状数组??
可惜并不知道怎么写,我们就可以考虑用平衡树裂点来维护矩阵。
然后就发现还有动态开点线段树的这种操作...
后来。。。其实一棵主席树完全可以干爆此题。。。。。。。
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
typedef long long ll;
struct node
{
int x,y;
}a[310000];
struct tree
{
int lc,rc;ll c;
}tr[6100000];int tail[310000],root[310000];
int tot=0;int size[6100000];
void insert(int &now,int l,int r,int k,ll num)
{
if(now==0) now=++tot;
if(l==r)
{
tr[now].c=num;
size[now]=0;
return ;
}
int mid=(l+r)/2;
if(k<=mid) insert(tr[now].lc,l,mid,k,num);
else insert(tr[now].rc,mid+1,r,k,num);
size[now]=size[tr[now].lc]+size[tr[now].rc];
}
ll findkth(int &now,int l,int r,int k,int &ans)
{
if(now==0) now=++tot;
if(l==r)
{
ans=l;
ll temp=tr[now].c;tr[now].c=0;
size[now]=1;
return temp;
}
int mid=(l+r)/2;ll temp;
if(mid-l+1-size[tr[now].lc]>=k)
{
temp=findkth(tr[now].lc,l,mid,k,ans);
}
else
{
temp=findkth(tr[now].rc,mid+1,r,k-(mid-l+1-size[tr[now].lc]),ans);
}
size[now]=size[tr[now].lc]+size[tr[now].rc];
return temp;
}
int main()
{
ll n,m,q;
scanf("%lld%lld%lld",&n,&m,&q);
for(int i=1;i<=n;i++) tail[i]=m-1;
tail[n+1]=n;
for(int i=1;i<=q;i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
if(a[i].y==m)
{
int temp2;
ll temp=findkth(root[n+1],1,n+q,a[i].x,temp2);
if(temp2<=n) temp=temp2*m;
printf("%lld\n",temp);
insert(root[n+1],1,n+q,++tail[n+1],temp);
}
else
{
int temp2;
ll temp=findkth(root[a[i].x],1,m+q,a[i].y,temp2);
if(temp2<m) temp=m*(a[i].x-1)+temp2;
printf("%lld\n",temp);
insert(root[n+1],1,n+q,++tail[n+1],temp);
temp=findkth(root[n+1],1,n+q,a[i].x,temp2);
if(temp2<=n) temp=temp2*m;
insert(root[a[i].x],1,m+q,++tail[a[i].x],temp);
}
}
return 0;
}