Queue-jumpers

一、题目

在这里插入图片描述

二、解法

这道题 n n n很大,但是询问数很小,我们考虑把所有给定的 x x x作为分割点,然后一个区间直接归为一个点,大小就为这个区间包含的点数,但是离散化时要注意,分割点可能有重复,详细看代码吧。

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <ctime>
#include <map>
using namespace std;
const int MAXN = 1000005;
int read()
{
	int x=0,flag=1;char c;
	while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
	while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return x*flag;
}
int T,n,q,rt,Index,a[MAXN],op[MAXN],v[MAXN];char s[20];
int ch[MAXN][2],val[MAXN],cnt[MAXN],siz[MAXN],hp[MAXN],l[MAXN];
map<int,int> mp;
struct node
{
    int p[2];
    node() {p[0]=p[1]=0;}
}emp;
void up(int x)
{
	siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+cnt[x];
}
node split(int x,int v)
{
    if(!x) return emp;
    int d=val[x]<=v;
    node y=split(ch[x][d],v);
    ch[x][d]=y.p[d^1];
    y.p[d^1]=x;
    up(x);
    return y;
}
node split_(int x,int s)
{
	if(!x) return emp;
	node y;
	if(siz[ch[x][0]]>=s)
	{
		y=split_(ch[x][0],s);
		ch[x][0]=y.p[1];
		y.p[1]=x;
	}
	else
	{
		y=split_(ch[x][1],s-siz[ch[x][0]]-cnt[x]);
		ch[x][1]=y.p[0];
		y.p[0]=x;
	}
	up(x);
	return y;
}
int merge(int x,int y)
{
	if(!x || !y) return x+y;
	if(hp[x]<hp[y])
	{
		ch[x][1]=merge(ch[x][1],y);
		up(x);
		return x;
	}
	ch[y][0]=merge(x,ch[y][0]);
	up(y);
	return y;
}
void ins(int v,int s,int L)
{
	int x=++Index; 
	cnt[x]=siz[x]=s;val[x]=v;l[x]=L;
	ch[x][0]=ch[x][1]=0;hp[x]=rand();
	rt=merge(rt,x);
}
int find(int x,int s)
{
	if(!x) return 0;
	if(siz[ch[x][0]]>=s)
		return find(ch[x][0],s);
	if(siz[ch[x][0]]+cnt[x]<s)
		return find(ch[x][1],s-siz[ch[x][0]]-cnt[x]);
	return s-siz[ch[x][0]]+l[x]-1;
}
int main()
{
	srand(time(0));
	T=read();int Case=0;
	while(T--)
	{
		n=read();q=read();
		rt=Index=0;
		printf("Case %d:\n",++Case);
		for(int i=1;i<=q;i++)
		{
			scanf("%s",s);
			a[i]=v[i]=read();
			if(s[0]=='T')
				op[i]=0;
			if(s[0]=='Q')
				op[i]=1;
			if(s[0]=='R')
				op[i]=2;
		}
		sort(a+1,a+1+q);
		int head=1,tail=1;
		for(int i=1;i<=q;i++)
		{
			if(a[i-1]+1<a[i])
			{
				ins(++tail,a[i]-a[i-1]-1,a[i-1]+1);
			}
			if(a[i]!=a[i-1])
			{
				mp[a[i]]=++tail;
				ins(tail,1,a[i]);
			}
		}
		if(a[q]!=n) ins(++tail,n-a[q],a[q]+1);
		for(int i=1;i<=q;i++)
		{
			if(op[i]==0)
			{
				node x=split(rt,mp[v[i]]-1),y=split_(x.p[1],1);
				mp[l[y.p[0]]]=--head;val[y.p[0]]=head;
				rt=merge(y.p[0],merge(x.p[0],y.p[1]));
			}
			if(op[i]==1)
			{
				node x=split(rt,mp[v[i]]);
				printf("%d\n",siz[x.p[0]]);
				rt=merge(x.p[0],x.p[1]);
			}
			if(op[i]==2)
			{
				printf("%d\n",find(rt,v[i]));
			}
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值