FZU 2100 排队

Description

一些人在排队买车票,假设每个人都有不同的买票紧急程度,如果某个人的紧急程度比排在他前一个的人的紧急程度更大,则这个人可以和前一个人调换位置,并且假设每个人都有一个耐心值,若某人的耐心值为x,则他最多可以向前调换x次,当然前提是他之前x个人的紧急程度都比他小,若遇到前面一个人紧急程度比他大的他将停止往前调换。现假设有N个人,按顺序一个个进入队列,并且每进去一个人立即按照紧急程度和其耐心值向前进行调换,调换停止后下一个人才进入队列。给出这N个人的紧急程度和耐心值,问最终的排队情况。

Input

第一行输入一个整数T,表示数据组数。接下来T组数据,对于每组数据,第一行输入一个整数n (1<=n<=10^5),接下来第2到n+1行每行输入两个整数a[i],c[i] (1<=a[i]<=n,0<=c[i]<=n),分别表示第i个人的紧急程度在n个人种排第几及其耐心值,a[i]越大表示紧急程度越大。

Output

对于每组数据,请输出一行n个数,以一个空格隔开,表示最终队列的排队情况,第i个数表示最终排在第i个位置的人是第几个进入队列的。

Sample Input

1
5
2 3
1 4
4 3
3 1
5 2

Sample Output

3 1 5 4 2

Source

FOJ有奖月赛-2012年11月
直接用splay去模拟操作过程,对于一个人,找到其耐心能到的最大位置,然后在这段区间里找最后一个优先级大于他的人,把这个人插在他后面。
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int mod = 1e9 + 7;
const int maxn = 2e5 + 10;
const int low(int x){ return x&-x; }
int T, n, x, y, flag;

struct Splays
{
	const static int maxn = 2e5 + 10;			//节点个数
	const static int INF = 0x7FFFFFFF;			//int最大值
	int ch[maxn][2], F[maxn], sz;				//左右儿子,父亲节点和节点总个数
	int S[maxn], M[maxn], A[maxn];
	int Node(int f, int a) { S[sz] = 1; A[sz] = M[sz] = a; ch[sz][0] = ch[sz][1] = 0; F[sz] = f; return sz++; }//申请一个新节点
	void clear(){ sz = 1; S[0] = ch[0][0] = ch[0][1] = F[0] = 0; M[0] = INF; }//清空操作
	void Count(int x)
	{
		M[x] = min(A[x], min(M[ch[x][0]], M[ch[x][1]]));
		S[x] = S[ch[x][0]] + S[ch[x][1]] + 1;
	}
	void rotate(int x, int k)
	{
		int y = F[x]; ch[y][!k] = ch[x][k]; F[ch[x][k]] = y;
		if (F[y]) ch[F[y]][y == ch[F[y]][1]] = x;
		F[x] = F[y];    F[y] = x;	ch[x][k] = y;
		M[x] = M[y];	S[x] = S[y];    Count(y);
	}
	void Splay(int x, int r)
	{
		for (int fa = F[r]; F[x] != fa;)
		{
			if (F[F[x]] == fa) { rotate(x, x == ch[F[x]][0]); return; }
			int y = x == ch[F[x]][0], z = F[x] == ch[F[F[x]]][0];
			y^z ? (rotate(x, y), rotate(x, z)) : (rotate(F[x], z), rotate(x, y));
		}
	}
	void build(int &x)
	{
		x = Node(0, 0);
		ch[x][1] = Node(x, INF);
	}
	void insert(int &x, int y, int z)
	{
		for (int i = x; i;)
		{
			if (y <= S[ch[i][0]]) { i = ch[i][0]; continue; }
			if (y == S[ch[i][0]] + 1) { Splay(i, x); x = i; break; }
			y -= S[ch[i][0]] + 1;	i = ch[i][1];
		}
		for (int i = ch[x][1]; i; i = ch[i][1])
		{
			if (!ch[i][1]) { Splay(i, ch[x][1]); break; }
		}
		int now = ch[ch[x][1]][0];
		S[x]++;	S[ch[x][1]]++;
		M[x] = min(M[x], z);	M[ch[x][1]] = min(M[ch[x][1]], z);
		if (!now){ ch[ch[x][1]][0] = Node(ch[x][1], z); return; }
		for (int i = ch[ch[x][1]][0]; i;)
		{
			S[i]++;	M[i] = min(z, M[i]);
			if (M[ch[i][1]] < z) { i = ch[i][1]; continue; }
			if (A[i] < z)
			{
				if (ch[i][1]) { i = ch[i][1]; continue; }
				else { now = ch[i][1] = Node(i, z); Splay(ch[i][1], x); break; }
			}
			else
			{
				if (ch[i][0]) { i = ch[i][0]; continue; }
				else { now = ch[i][0] = Node(i, z); Splay(ch[i][0], x); break; }
			}
		}
		x = now;
	}
	void dfs(int x)
	{
		if (!x) return;
		dfs(ch[x][0]);
		if (x>2)
		{
			if (flag) printf(" "); else flag = 1;
			printf("%d", x - 2);
		}
		dfs(ch[x][1]);
	}
}solve;

int main()
{
	scanf("%d", &T);
	while (T--)
	{
		int root = 0; solve.clear();
		solve.build(root);
		scanf("%d", &n);
		for (int i = 1; i <= n; i++)
		{
			scanf("%d%d", &x, &y);
			solve.insert(root, max(1, i - y), n + 1 - x);
		}
		flag = 0;	solve.dfs(root);
		printf("\n");
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值