POJ - 2828 Buy Tickets (线段树)
Railway tickets were difficult to buy around the Lunar New Year in China, so we must get up early and join a long queue…
The Lunar New Year was approaching, but unluckily the Little Cat still had schedules going here and there. Now, he had to travel by train to Mianyang, Sichuan Province for the winter camp selection of the national team of Olympiad in Informatics.
It was one o’clock a.m. and dark outside. Chill wind from the northwest did not scare off the people in the queue. The cold night gave the Little Cat a shiver. Why not find a problem to think about? That was none the less better than freezing to death!
People kept jumping the queue. Since it was too dark around, such moves would not be discovered even by the people adjacent to the queue-jumpers. “If every person in the queue is assigned an integral value and all the information about those who have jumped the queue and where they stand after queue-jumping is given, can I find out the final order of people in the queue?” Thought the Little Cat.
There will be several test cases in the input. Each test case consists of N + 1 lines where N (1 ≤ N ≤ 200,000) is given in the first line of the test case. The next N lines contain the pairs of values Posi and Vali in the increasing order of i (1 ≤ i ≤ N). For each i, the ranges and meanings of Posi and Vali are as follows:
- Posi ∈ [0, i − 1] — The i-th person came to the queue and stood right behind the Posi-th person in the queue. The booking office was considered the 0th person and the person at the front of the queue was considered the first person in the queue.
- Vali ∈ [0, 32767] — The i-th person was assigned the value Vali.
There no blank lines between test cases. Proceed to the end of input.
For each test cases, output a single line of space-separated integers which are the values of people in the order they stand in the queue.
4 0 77 1 51 1 33 2 69 4 0 20523 1 19243 1 3890 0 31492Sample Output
77 33 69 51 31492 20523 3890 19243
题意:现在有n个人要排队,按顺序进行入队操作,(i个人入队后,保证站的前i个位置)每行给出它站在x号位的后面,以及它的权值为y,
如果他入队的位置已经有人,则他站这个位置,后面的人依次向后移动。
最后要求依次输出,队列中人的权值
分析:如果一个人在某次操作入队以后,那么如果后面的人站到了他的位置或者他的前面,那么它的位置将发生改变。
但逆序,从后往前看的,当这个人出现的时候,那么它的位置就已经固定了,比如它入队的位置是5号位,而2号位,4号位已经被占了
那么他只能到7号位,因为他入队时是5,后面出现的2和4一定会将它往后移动。换句话说,也就是它必然站在队里的第5个空位上。
这样的话,我们需要维护区间空位的数量,以便找到指定的空位。这里用到了线段树来进行维护。
代码如下:
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <cmath> using namespace std; const int MAXN=2e5+10; int sum[MAXN<<2]; int res[MAXN]; int n; struct Node { int x; int val; }op[MAXN]; struct node { int l; int r; int num; }tree[MAXN<<2]; void PushUp(int rt) { tree[rt].num=tree[rt<<1].num+tree[rt<<1|1].num; } void BuildTree(int l,int r,int rt) { tree[rt].l=l; tree[rt].r=r; if(l==r) { tree[rt].num=1; return; } int mid=(tree[rt].l+tree[rt].r)/2; BuildTree(l,mid,rt<<1); BuildTree(mid+1,r,rt<<1|1); PushUp(rt); } void Insert(int x,int rt,int val) { int l=tree[rt].l; int r=tree[rt].r; if(l==r) //范围缩小到一个点位,则放入该点位 { tree[rt].num--; res[l]=val; return; } if(x<=tree[rt<<1].num)//左节点空位数量满足,考虑左节点 Insert(x,rt<<1,val); else Insert(x-tree[rt<<1].num,rt<<1|1,val);//左节点数量不满足,考虑右节点 tree[rt].num--; } int main() { int a,b; while(scanf("%d",&n)!=EOF) { BuildTree(1,n,1); for(int i=1;i<=n;i++) scanf("%d%d",&op[i].x,&op[i].val); for(int i=n;i>=1;i--) Insert(op[i].x+1,1,op[i].val);//题目中给的是在x的后面,所以位置编号是x+1 for(int i=1;i<=n;i++) i==1?printf("%d",res[i]):printf(" %d",res[i]); printf("\n"); } return 0; }