[NOIP2017 提高组] 列队

考虑我们需要维护的是这样一个东西。

即可能变化的只有每一行前\(m - 1\)个,和最后一列。

我们考虑对每一行开一个权值线段树,记录原本序列的第\(x\)个是否被一出,且用一个\(vector\)记录多出的部分。
那么很好维护的。

考虑内存的问题,我们用动态开点就行了。

#include<iostream>
#include<cstdio>
#include<vector>
#define ll long long 
#define N 300005

ll root[N]; 

struct P{
	ll l,r,v;
}e[N << 4];

std::vector<ll>QWQ[N + 1];

ll n,m,q,lim;

#define mid ((l + r) >> 1)
#define ls(x) e[x].l
#define rs(x) e[x].r


inline ll qi(ll u,int l,int r,int p){
	if(l == r){
		return l;
	}
	ll tmp = mid - l + 1 - e[ls(u)].v;
	if(p <= tmp)
	return qi(ls(u),l,mid,p);
	else
	return qi(rs(u),mid + 1,r,p - tmp);
}

ll cnt;

inline void change(ll &u,int l,int r,int p){
	if(!u)u = ++cnt;
	e[u].v ++ ;
	if(l == r)
	return ;
	if(p <= mid)
	change(ls(u),l,mid,p);
	else
	change(rs(u),mid + 1,r,p);
}


inline ll del1(int x,ll y){
	ll pos = qi(root[n + 1],1,lim,x);
	change(root[n + 1],1,lim,pos);
	ll ans = pos <= n ? 1ll * pos * m : QWQ[n + 1][pos - n - 1];
	return QWQ[n + 1].push_back(y ? y : ans),ans;
}

inline ll del2(int x,int y){
	ll pos = qi(root[x],1,lim,y);
	change(root[x],1,lim,pos);
	ll ans = pos < m ? 1ll * (x - 1) * m + pos : QWQ[x][pos - m];
	return QWQ[x].push_back(del1(x,ans)),ans;
}

int main(){
	scanf("%lld%lld%lld",&n,&m,&q);
	lim = std::max(n,m) + q;
	while(q -- ){
		ll x,y;
		scanf("%lld%lld",&x,&y);
		if(y == m)
		std::cout<<del1(x,0)<<std::endl;
		else
		std::cout<<del2(x,y)<<std::endl;
	}
}
posted @ 2021-08-03 21:21  fhq_treap  阅读(66)  评论(0编辑  收藏  举报