jzoj5478. 【NOIP2017提高组】列队

来源:互联网 发布:ssh弱算法支持 漏洞 编辑:程序博客网 时间:2024/06/06 02:51

题意

一个n*m的矩阵,每个位置上有一个编号,每次取出一个编号(a,b),将(a,k) k>b左移一位,(z,m) z>a上移一位。 (左上角1,1),然后将取出的编号放在(n,m).
n,m<=3e5
询问数q<=3e5

分析

关注的是当前修改这一行和最后一列。

发现每一次修改都只是修改个别点的位置,这一行和最后一列其他点的相对位置是不变的
考虑n颗动态开点的线段树(1..m+预留的q个位置),还有一颗额外维护一下最后一列(1..n+q)。
每一次修改只需要
1. 线段树上二分找到第x个数
2. 加、改常数个点
因此线段树点数就是O(q log (n+q)),动态开点写的好可以开到6e6,写的炸就2e7.

时间复杂度是O(q log (n+q))

#include <cstdio>#include <iostream>using namespace std;const int N = 3e5+10,MXP = 5500000;typedef long long ll;ll n,m,q;int root[N],lc[MXP],rc[MXP],size[MXP],tot;int tail[N];ll v[MXP];void set(int &x,int l,int r,int tg,ll va=0) {    if (!x) x=++tot;    if (l==r) {        v[x]=va;        return;    }    if (tg<=(l+r>>1)) set(lc[x],l,l+r>>1,tg,va);     else set(rc[x],(l+r>>1)+1,r,tg,va);    size[x]=size[lc[x]]+size[rc[x]];}ll kth(int &x,int l,int r,int tg,int &ret) {    if (!x) x=++tot;    if (l==r) {        ret=l;        size[x]=1;        return v[x];    }    ll mid=l+r>>1,rrr;    if (mid-l+1-size[lc[x]]>=tg) rrr=kth(lc[x],l,mid,tg,ret);    else rrr=kth(rc[x],mid+1,r,tg-(mid-l+1-size[lc[x]]),ret);    size[x]=size[lc[x]]+size[rc[x]];    return rrr;}int main() {    freopen("phalanx.in","r",stdin);    freopen("phalanx.out","w",stdout);    cin>>n>>m>>q;    for (int i=1; i<=n; i++) tail[i]=m-1;    tail[n+1]=n;    int loc,x,y;    ll tmp;    for (int i=1; i<=q; i++) {        scanf("%d %d",&x,&y);        if (y==m) {            tmp=kth(root[n+1],1,n+q,x,loc);            if (loc<=n) tmp=loc*m;            printf("%lld\n",tmp);            set(root[n+1],1,n+q,++tail[n+1],tmp);        } else {            tmp=kth(root[x],1,m+q,y,loc);            if (loc<m) tmp=(x-1)*m+loc;            printf("%lld\n",tmp);            set(root[n+1],1,n+q,++tail[n+1],tmp);            tmp=kth(root[n+1],1,n+q,x,loc);            if (loc<=n) tmp=loc*m;            set(root[x],1,m+q,++tail[x],tmp);        }    }    //cout<<tot<<endl;}
原创粉丝点击