【题解】[NOIP2017 提高组] 列队

题意

给定一个 n*m 的队列,每次操作选取一个位置 (i,j) 出队,然后填补空位。输出每次出队的编号。

Solution:

考点:模拟+数据结构。

算法一

对于 n,m<=1000 的数据,直接暴力模拟;

对于 n=1 的数据,可以树状数组维护:

请添加图片描述
稍加修改,可以得到 x=1 的做法,

请添加图片描述
期望得分 60pts

算法二

再来看 n=2 的情况:
请添加图片描述
于是不难得到下述算法:

  1. 建立一个以第 m 行为元素的序列
  2. 对于每次操作,判断是否在当前行内,如果是则先在当前行内删除,再插入列尾;否则在列中查询排名 x 的数,先将它删去,然后插入列尾。如果是第一种情况就要把列中排名 x 的数插到行中去。

比较棘手的是空间会爆。观察到被删除的节点只有 q 个,所以可以 动态开点+线段树二分 ,只有一个 log

可以用 线段树 实现。时间复杂度 O(nlogn)

纯属口胡,不喜勿喷。

#include<bits/stdc++.h> #define INF 1e9 #define ll long long #define PII pair<ll,int> #define All(a) a.begin(),a.end() #define L t[p].lson #define R t[p].rson using namespace std; const int mx=4e7+5; inline int read() { int x=0,f=1; char c=getchar(); while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();} return x*f; } int n,m,q,cnt[mx],tot; ll res; struct SegmentTree{ int lson,rson,siz,add; ll val; }t[mx]; void PushUp(int p) { t[p].siz=t[L].siz+t[R].siz; } void update(int p,int l,int r,int x,ll y) { if(l==r) { t[p].val=y; t[p].siz=1; return; } int mid=l+r>>1; if(!t[p].lson) t[p].lson=++tot; if(!t[p].rson) t[p].rson=++tot; if(t[p].add) { t[p].add=0; t[L].siz=mid-l+1; t[L].add=1; t[R].siz=r-mid; t[R].add=1; } if(x<=mid) { update(L,l,mid,x,y); } else { update(R,mid+1,r,x,y); } PushUp(p); } int query(int p,int l,int r,int x) { if(l==r) { return l; } int mid=l+r>>1; if(!t[p].lson) t[p].lson=++tot; if(!t[p].rson) t[p].rson=++tot; if(t[p].add) { t[p].add=0; t[L].siz=mid-l+1; t[L].add=1; t[R].siz=r-mid; t[R].add=1; } if(x<=t[L].siz) return query(L,l,mid,x); return query(R,mid+1,r,x-t[L].siz); } void Delete(int p,int l,int r,int x) { if(l==r) { t[p].siz=0; res=t[p].val; return; } int mid=l+r>>1; if(!t[p].lson) t[p].lson=++tot; if(!t[p].rson) t[p].rson=++tot; if(t[p].add) { t[p].add=0; t[L].siz=mid-l+1; t[L].add=1; t[R].siz=r-mid; t[R].add=1; } if(x<=mid) Delete(L,l,mid,x); else Delete(R,mid+1,r,x); PushUp(p); } void build(int p,int l,int r,int ql,int qr) { if(ql<=l&&r<=qr) { t[p].siz=r-l+1; t[p].add=1; return; } if(!t[p].lson) t[p].lson=++tot; if(!t[p].rson) t[p].rson=++tot; int mid=l+r>>1; if(ql<=mid) build(L,l,mid,ql,qr); if(mid<qr) build(R,mid+1,r,ql,qr); PushUp(p); } int main() { n=read(),m=read(),q=read(); tot=n+1; for(int i=1;i<=n;i++) { build(i,1,m+q,1,m-1); cnt[i]=m-1; } for(int i=1;i<=n;i++) { update(n+1,1,n+q,i,1ll*i*m); } for(int i=1;i<=q;i++) { int x=read(),y=read(); if(y<=m-1) { int z=query(x,1,m+q,y); Delete(x,1,m+q,z); ll tmp; if(z<=m) tmp=1ll*(x-1)*m+z; else tmp=res; printf("%lld\n",tmp); z=query(n+1,1,n+q,x); Delete(n+1,1,n+q,z); update(x,1,m+q,m+i-1,res); update(n+1,1,n+q,n+i,tmp); } else { int z=query(n+1,1,n+q,x); Delete(n+1,1,n+q,z); printf("%lld\n",res); update(n+1,1,n+q,n+i,res); } } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530302.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(95)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示