【题解】[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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值