luogu3960&&loj2319 列队

84 篇文章 0 订阅
31 篇文章 0 订阅

http://www.elijahqi.win/2018/02/15/luogu3960loj2319/
题目描述
Sylvia 是一个热爱学习的女♂孩子。
前段时间,Sylvia 参加了学校的军训。众所周知,军训的时候需要站方阵。
Sylvia 所在的方阵中有n×m 名学生,方阵的行数为 n ,列数为 m 。
为了便于管理,教官在训练开始时,按照从前到后,从左到右的顺序给方阵中 的学生从 1 到 n×m 编上了号码(参见后面的样例)。即:初始时,第 i 行第 j 列 的学生的编号是(i−1)×m+j 。
然而在练习方阵的时候,经常会有学生因为各种各样的事情需要离队。在一天 中,一共发生了 q 件这样的离队事件。每一次离队事件可以用数对(x,y)(1≤x≤n,1≤y≤m) 描述,表示第 x 行第 y 列的学生离队。
在有学生离队后,队伍中出现了一个空位。为了队伍的整齐,教官会依次下达 这样的两条指令:

向左看齐。这时第一列保持不动,所有学生向左填补空缺。不难发现在这条 指令之后,空位在第 x 行第 m 列。
向前看齐。这时第一行保持不动,所有学生向前填补空缺。不难发现在这条 指令之后,空位在第 n 行第 m 列。

教官规定不能有两个或更多学生同时离队。即在前一个离队的学生归队之后, 下一个学生才能离队。因此在每一个离队的学生要归队时,队伍中有且仅有第 n 行 第 m 列一个空位,这时这个学生会自然地填补到这个位置。
因为站方阵真的很无聊,所以 Sylvia 想要计算每一次离队事件中,离队的同学 的编号是多少。
注意:每一个同学的编号不会随着离队事件的发生而改变,在发生离队事件后 方阵中同学的编号可能是乱序的。
输入输出格式
输入格式:
输入共 q+1 行。
第 1 行包含 3 个用空格分隔的正整数 n,m,q ,表示方阵大小是 n 行 m 列,一共发 生了 q 次事件。
接下来 q 行按照事件发生顺序描述了 q 件事件。每一行是两个整数 x,y ,用一个空 格分隔,表示这个离队事件中离队的学生当时排在第 x 行第 y 列。
输出格式:
按照事件输入的顺序,每一个事件输出一行一个整数,表示这个离队事件中离队学 生的编号。
输入输出样例
输入样例#1: 复制
2 2 3 1 1 2 2 1 2
输出样例#1: 复制
1 1 4
说明
【输入输出样例 1 说明】
列队的过程如上图所示,每一行描述了一个事件。 在第一个事件中,编号为 1 的同学离队,这时空位在第一行第一列。接着所有同学 向左标齐,这时编号为 2 的同学向左移动一步,空位移动到第一行第二列。然后所有同 学向上标齐,这时编号为 4 的同学向上一步,这时空位移动到第二行第二列。最后编号 为 1 的同学返回填补到空位中。
【数据规模与约定】
数据保证每一个事件满足 1≤x≤n,1≤y≤m
据说暴力有80分 前面30分直接暴力模拟即可 如果只有一行的话那就开一个两倍的线段树 每次二分一下前面有几个 然后就可以找到了 然后根据每次询问把现在的扔到最后面 如果是只针对第一行询问 那么我针对最后一列开个队列模拟一下这个每次都在后面插入前面弹出..我的做法太麻烦了被zhx巨佬diss过 qwq说我写的太过于冗长了

#include<cstdio>
#include<algorithm>
#include<deque>
using namespace std;
#define ll long long
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0;char ch=gc();
    while (ch<'0'||ch>'9') ch=gc();
    while (ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=gc();}
    return x;
}
int mm[55000],n,m,q;
long long line[550][55000];
long long column[55000];
struct node{
    int left,right,sum;ll v;
}tree[3000000];
int num,root;
inline void update(int x){
    int l=tree[x].left,r=tree[x].right;
    tree[x].sum=tree[l].sum+tree[r].sum;
}
void build(int &x,int l,int r){
    x=++num;
    if (l==r&&r<=m){tree[x].sum=1;tree[x].v=l;return;}
    if (l==r){tree[x].sum=0;tree[x].v=0;return;}
    int mid=l+r>>1;
    build(tree[x].left,l,mid);build(tree[x].right,mid+1,r);
    update(x);
}
ll query(int x,int l,int r,int p){
    if (l==r) {ll tmp=tree[x].v;tree[x].v=0;tree[x].sum=0;return tmp;}
    int mid=l+r>>1;
    if (tree[tree[x].left].sum<p) {
        ll tmp=query(tree[x].right,mid+1,r,p-tree[tree[x].left].sum);
        update(x);return tmp;
    }else {
        ll tmp=query(tree[x].left,l,mid,p);update(x);return tmp;
    }
}
void insert1(int x,int l,int r,int p,ll v){
    if (l==r){tree[x].v+=v;tree[x].sum=1;return;}
    int mid=l+r>>1;
    if(p<=mid) insert1(tree[x].left,l,mid,p,v) ;
    else insert1(tree[x].right,mid+1,r,p,v);
    update(x);
}
void print(int x,int l,int r){
    int mid=l+r>>1;
    if (tree[x].left) print(tree[x].left,l,mid);
    if (l==r) printf("%lld ",tree[x].v,tree[x].sum);
    if (tree[x].right) print(tree[x].right,mid+1,r);
}
int main(){
//  freopen("phalanx15.in","r",stdin);
    n=read();m=read();q=read();
    if (q<=500){
        for (int i=1;i<=n;++i) column[i]=(ll)m*i;
        for (int i=1;i<=q;++i){
            int x=read(),y=read();
            if (!mm[x]){
                mm[x]=++num;
                for (int j=1;j<=m-1;++j) line[num][j]=(ll)(x-1)*m+j;
                if (y==m) {
                    printf("%lld\n",column[x]);ll tmp=column[x];
                    for (int j=x;j<n;++j) column[j]=column[j+1];column[n]=tmp;
                }else{
                    printf("%lld\n",(ll)(x-1)*m+y);
                    for (int j=y;j<m;++j) line[mm[x]][j]=line[mm[x]][j+1];
                    for (int j=x;j<n;++j) column[j]=column[j+1];column[n]=(ll)(x-1)*m+y;
                }
            }else{
                if (y==m) {
                    printf("%lld\n",column[x]);ll tmp=column[x];
                    for (int j=x;j<n;++j) column[j]=column[j+1];column[n]=tmp;
                }else{
                    printf("%lld\n",line[mm[x]][y]);
                    for (int j=y;j<m;++j) line[mm[x]][j]=line[mm[x]][j+1];
                    for (int j=x;j<n;++j) column[j]=column[j+1];column[n]=(ll)(x-1)*m+y;
                }
            }
        }
        return 0;
    }
    deque<ll> qq;
    for (int i=1;i<=n;++i) qq.push_back((ll)i*m);
    build(root,1,2*m);int now=m+1;
    for (int i=1;i<=q;++i){
        int x=read(),y=read();
        ll id=query(root,1,2*m,y);printf("%lld\n",id);qq.pop_front();qq.push_back(id);
        insert1(root,1,2*m,now++,qq.front());//printf("%lld %lld\n",qq.front(),qq.back());
        //print(root,1,2*m);printf("\n");
    }
    return 0;
}

暴力+splay
按照题意 我观察到其实我每次只不过是把一个横行中的一个取出来 然后再把这一行整体前移 把我取出来的这个放入(n,m)这个位置 那么可以发现 我可以针对最后一列用一个splay维护 然后再针对前面每一行用一个splay维护即可 但是题目中的点太大 怎么办 开不下啊 那就用leoly在nkoi round5里的绝技 动态拆点splay 相当于一开始我每个节点是一个区间 然后要用的时候把他拆成3段 分别插回去即可 大概大小是和询问次数成线性关系的 那么我在每个节点上维护一下起点和终点 然后我再算一算我这次要询问的点会出现在哪一段上 然后取出来 然后把中间的取出来 然后再分成两段 把原来的一段改成左段 右段直接插在左段的左边 即可 这题我的常数太大..要是真的是考场上 ccf的老爷机肯定跑步过去.. loj因为常数太大我都卡常卡了一天 菜死了啊 注意拆的时候可能左边没有或者右边没有 然后我这个查找的时候要回传他前面有几个节点所以要注意很多细节 细节看代码Okay 同样还是冗长qwq

#include<queue>
#include<cstdio>
#include<algorithm>
#define N 3300000
#define ll long long
#define pa pair<int,int>
#define fi first
#define se second
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();}
    while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int n,m,q,fa[N],c[N][2],rt[N],size[N],cnt,num[N];ll st[N],ed[N];
struct node{
    ll st,ed;int len;
};
inline void update(int x){
    size[x]=size[c[x][0]]+size[c[x][1]]+num[x];
}
inline void rotate(int x,int &tar){
    int y=fa[x],z=fa[y];
    if (y==tar) tar=x;else c[z][c[z][1]==y]=x;
    int l=c[y][1]==x,r=l^1;
    fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
    c[y][l]=c[x][r];c[x][r]=y;update(y);update(x);
}
inline void splay(int x,int &tar){
    while(x!=tar){
        int y=fa[x],z=fa[y];
        if (y!=tar){
            if (c[y][0]==x^c[z][0]==y) rotate(x,tar);else rotate(y,tar);
        }rotate(x,tar);
    }
}
inline int find(int x,int p){
    int l=c[x][0],r=c[x][1];
    if (size[l]<p&&p<=size[l]+num[x]) return x;
    if (p<=size[l]) return find(l,p);else return find(r,p-size[l]-num[x]);
}
inline pa find1(int x,int p,int sz){
    int l=c[x][0],r=c[x][1];
    if (p>size[l]&&p<=size[l]+num[x]) return make_pair(sz+size[l],x);
    if (p<=size[l]) return find1(l,p,sz);else return find1(r,p-size[l]-num[x],sz+size[l]+num[x]);
}
inline void insert1(int id,int x,int y,node v){
    int xx=find(rt[id],x),yy=find(rt[id],y);
    splay(yy,rt[id]);splay(xx,c[yy][0]);fa[++cnt]=xx;st[cnt]=v.st;ed[cnt]=v.ed;
    size[cnt]=num[cnt]=v.len;c[xx][1]=cnt;update(xx);update(fa[xx]);
}
inline int split(int id,int x,int y){
    int xx=find(rt[id],x),yy=find(rt[id],y);
    splay(yy,rt[id]);splay(xx,c[yy][0]);return c[xx][1];
} 
inline void del(int t){
    c[fa[t]][1]=0;update(fa[t]);update(fa[fa[t]]);
}
int main(){
//  freopen("phalanx2.in","r",stdin);
//  freopen("phalanx2.out","w",stdout);
    n=read();m=read();q=read();
    for (int i=0;i<=n;++i){
        rt[i]=++cnt;size[rt[i]]=2;num[cnt]=1;
        c[rt[i]][0]=++cnt;fa[cnt]=rt[i];size[cnt]=1;num[cnt]=1;
        if (i>=1&&i<=n) {
            node tmp;tmp.st=tmp.ed=(ll)i*m;tmp.len=1;
            insert1(0,i,i+1,tmp);tmp.st=(ll)(i-1)*m+1;
            tmp.ed=(ll)i*m-1;tmp.len=m-1;insert1(i,1,2,tmp);    
        }
    }
    for (int i=1;i<=q;++i){
        int x=read(),y=read();node tmp;
        if (y==m){
            int t=split(0,x,x+2);tmp.st=st[t];
            tmp.ed=ed[t];tmp.len=1;del(t);
            insert1(0,size[rt[0]]-1,size[rt[0]],tmp);
            printf("%lld\n",tmp.st);continue;
        }node tmp1,tmp2,tmp3;
        pa t=find1(rt[x],y+1,0);int pre=t.fi,succ=t.fi+num[t.se]+1;
        int tt=split(x,pre,succ);int t1=split(0,x,x+2);tmp3.len=1;tmp3.st=st[t1];tmp3.ed=ed[t1];
        int len=y-t.fi;ll v=st[t.se]+len;tmp.st=v;tmp.ed=v;tmp.len=1;del(t1);printf("%lld\n",v);
        tmp1.st=st[t.se],tmp1.ed=st[t.se]+len-1;if (tmp1.ed<tmp1.st) tmp1.len=0;else tmp1.len=tmp1.ed-tmp1.st+1;
        tmp2.ed=ed[t.se],tmp2.st=st[t.se]+len+1;if (tmp2.ed<tmp2.st) tmp2.len=0;else tmp2.len=tmp2.ed-tmp2.st+1;
        if (tmp1.len&&tmp2.len){
            int tp;ed[tt]=tmp1.ed;num[tt]=size[tt]=tmp1.len;c[tt][1]=++cnt;tp=cnt;fa[tp]=tt;
            int f=fa[tt],gf=fa[f];num[tp]=size[tp]=tmp2.len;st[tp]=tmp2.st;ed[tp]=tmp2.ed;
            update(tt);update(f);update(gf);
        }else{
            if (tmp1.len) {
                num[tt]=size[tt]=tmp1.len;st[tt]=tmp1.st;ed[tt]=tmp1.ed;update(fa[tt]);update(rt[x]);
            }
            if (tmp2.len) {
                num[tt]=size[tt]=tmp2.len;st[tt]=tmp2.st;ed[tt]=tmp2.ed;update(fa[tt]);update(rt[x]);
            }
            if (!tmp1.len&&!tmp2.len) del(tt);
        }
        int xx=find(rt[x],size[rt[x]]-1);splay(xx,rt[x]);
        int tp=c[rt[x]][1];c[tp][0]=++cnt;fa[cnt]=tp;
        st[cnt]=ed[cnt]=tmp3.st;num[cnt]=size[cnt]=1;
        update(tp);update(rt[x]);
        xx=find(rt[0],size[rt[0]]-1);splay(xx,rt[0]);
        tp=c[rt[0]][1];c[tp][0]=++cnt;fa[cnt]=tp;
        st[cnt]=ed[cnt]=tmp.st;num[cnt]=size[cnt]=1;
        update(tp);update(rt[0]);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值