[NOIP2017 提高组] 列队 题解

数据结构。

n = 1 n=1 n=1 的 case:考虑有 m + q m+q m+q 个位置,每次操作队移,出队人直接插入队尾。维护位置对应的人,每次查询第 k k k 个人的位置 p p p,输出 p p p 位置对应的人,并将出对者加入队尾。

实现考虑维护 01 序列,表示位置上是 / 否有人,每次查前缀和为 k k k 的位置即可。

一般情况:每次操作只会影响某一行以及最后一列。考虑将最后一列单独处理。

对于查询 ( x , y ) (x,y) (x,y):需查询第 x x x 行第 y y y 个人的位置以及最后一列第 x x x 个人的位置( y = m y = m y=m 时只用查最后一列),同 n = 1 n=1 n=1 的 case 维护一下对应编号即可。

实现考虑离线树状树组或动态开点线段树,线段树 / 树状树组上二分可以做到 log ⁡ \log log,总时间复杂度 O ( n log ⁡ n ) O(n \log n) O(nlogn)

树状树组实现显然要离线,仅用一个 BIT 预处理每次非最后一列操作在对应行的位置。

#include<bits/stdc++.h>
#define int long long
using namespace std;

const int N = 3e5 + 5; 
const int V = 6e5;

int n, m, q, tree[N<<1], x[N], y[N], num[N];

int lowbit(int x) {return x&(-x);}
void add(int x, int d){for(;x <= V; x += lowbit(x)) tree[x] += d;}
int select(int k)
{
	int pos = 0, sum = 0;
	for(int i=20; i>=0; i--)
	{
		pos += (1 << i);
		if(pos > V or sum + tree[pos] >= k) pos -= (1 << i);
		else sum += tree[pos];
	}
	return pos + 1;
}

signed main()
{
	ios::sync_with_stdio(0); cin.tie(0);
	
	cin >> n >> m >> q;
	
	for(int i=1; i<=V; i++) tree[i] = lowbit(i);
	
	vector <vector<int>> cmd(n+1);
	
	for(int i=1; i<=q; i++)
	{
		cin >> x[i] >> y[i];
		if(y[i] != m) cmd[x[i]].push_back(i);
	}
	
	for(int i=1; i<=n; i++)
	{
		for(auto id : cmd[i])
			num[id] = select(y[id]), add(num[id], -1);
			
		for(auto id : cmd[i]) 
			add(num[id], 1);
	}
	
	vector <vector<int>> row(n+1);
	vector <int> column;
	
	for(int i=1; i<=q; i++)
	{
		int in, out, p = select(x[i]); 
        add(p, -1);
		if(y[i] != m)
		{
			out = (num[i] < m) ? ((x[i]-1)*m+num[i]) : row[x[i]][num[i]-m], 
            in = (p <= n) ? (p*m) : column[p-n-1];
			row[x[i]].push_back(in), column.push_back(out);
		}
		else
		{
			out = (p <= n) ? (p*m) : column[p-n-1];
			column.push_back(out);
		}
		cout << out << "\n";	
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值