题意
给定一个 n*m
的队列,每次操作选取一个位置 (i,j)
出队,然后填补空位。输出每次出队的编号。
Solution:
考点:模拟+数据结构。
算法一
对于 n,m<=1000
的数据,直接暴力模拟;
对于 n=1
的数据,可以树状数组维护:
稍加修改,可以得到 x=1
的做法,
期望得分 60pts
。
算法二
再来看 n=2
的情况:
于是不难得到下述算法:
- 建立一个以第
m
行为元素的序列 - 对于每次操作,判断是否在当前行内,如果是则先在当前行内删除,再插入列尾;否则在列中查询排名
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