链接:http://poj.org/problem?id=2828
题意:
一个排队的队列
T组操作
每次输入a b表示在第a个人后面插队,插队的人是b
最后输出整个队伍的顺序
思路:
采用从后往前推的思路,往队列中填人
在代码里解释的很清楚了,很好的题目!!
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<string>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<ctime>
using namespace std;
#define lson l,m,rt*2
#define rson m+1,r,rt*2+1
#define calm (l+r)/2
#define maxn 200010
struct node{
int pos, val;
};
int sum[maxn * 4];
int ans[maxn];
node op[maxn];
void build(int l, int r, int rt)//建树的时候就保存当前区间里剩余多少空位
{
sum[rt] = r - l + 1;
if (l == r)
return;
int m = calm;
build(lson);
build(rson);
}
/*
填入的时候,知道是第几个人,实际就是从前往后数的第几个人
那么找人的时候,要么填入左子树,要么填入右子树
填入左子树的时候编号不变
但是填入右子树的时候,编号就发生改变了,要减去原先左子树里面的人
才是他在右子树里的编号
*/
void update(int pos, int val, int l, int r, int rt)
{
if (l == r)//填到叶子节点的时候,当前的l和r就是他在整个队列中的位置,所以可以直接填入ans数组
{
sum[rt] = 0;//把当前位子的位子-1
ans[l] = val;
return;
}
int m = calm;
if (pos <= sum[rt * 2])//填入的人是第pos个人,如果左子树里没有pos个空位,那么就无法填入左树
update(pos, val, lson);
else update(pos - sum[rt * 2], val, rson);
sum[rt]--;//填入以后每一层人数-1
}
int main()
{
// freopen("D://input.txt", "r", stdin);
// freopen("D://output.txt", "w", stdout);
int n;
while (scanf("%d", &n) != EOF)
{
build(1, n, 1);//以第1个人到第n个人建树
int i;
for (i = 0; i < n; i++)
{
scanf("%d%d", &op[i].pos, &op[i].val);
}
/*
倒着来的原因是:
最后输入的那个编号,如果是0,那么他一定是整个队列中的第一个人
所以倒着推可以避免插队操作,直接按最后的顺序一个个填就行了
不理解的可以手动模拟一遍
*/
for (i = n - 1; i >= 0; i--)
{
update(op[i].pos + 1, op[i].val, 1, n, 1);//输入0的时候实际是第一个人,所以输入编号+1
}
for (i = 1; i <= n; i++)
{
if (i != 1)
printf(" ");
printf("%d", ans[i]);
}
printf("\n");
}
// printf("\n%.3lf\n",clock()/CLOCKS_PER_SEC);
return 0;
}