POJ 2828 Buy Tickets(线段树单点)

https://vjudge.net/problem/POJ-2828

题目意思:有n个数,进行n次操作,每次操作有两个数pos, ans。pos的意思是把ans放到第pos 位置的后面,pos后面的数就往后推一位。最后输出每个位置的ans。

思路:根据题 目可知,最后插入的位置的数才是最终不变的数,所以可以从最后的输入作第1个放入,依此类推,倒插入。在插入时也有一定的技术,首先创建一棵空线段树时,每个节点记录当前范围内有多少个空位置。在插入时,要注意,一个数放入之后那么这个位置就不用管了,那么树中所有的空位置就是余下的数所对应的位置,也就是把余下的数又可以看作是一个新的集合。那么每次插入都是当前集合的第1次放。

 1 #include <iostream>
2 #include <algorithm>
3 #include <string>
4 #include <sstream>
5 #include <set>
6 #include <vector>
7 #include <stack>
8 #include <map>
9 #include <queue>
10 #include <deque>
11 #include <cstdlib>
12 #include <cstdio>
13 #include <cstring>
14 #include <cmath>
15 #include <ctime>
16 #include <functional>
17 // #include <bits/stdc++.h>
18 using namespace std;
19
20 int n,ans[1000000];
21
22 struct node
23 {
24 int n,val;
25 }a[1000000];
26
27 struct tree
28 {
29 int l,r,n;
30 }b[1000000];
31
32 void init()
33 {
34 int i,j,k;
35 for(k=1;k<n;k<<=1);
36 for(i=k;i<2*k;i++)
37 {
38 b[i].l=b[i].r=i-k+1;
39 b[i].n=1;//每个叶子节点只能放入一个人
40 }
41 for(i=k-1;i>0;i--)
42 {
43 b[i].l=b[2*i].l;
44 b[i].r=b[2*i+1].r;
45 b[i].n=b[2*i].n+b[2*i+1].n;//每个区间是其左右子树所能放入的人数总和
46 }
47 }
48
49 void insert(int i,int x,int m)
50 {
51 if(b[i].l==b[i].r)//找到叶子节点,这个节点存放该人,并且叶子节点能放入的人数清0
52 {
53 ans[b[i].l]=m;
54 b[i].n=0;
55 return;
56 }
57 if(x<=b[2*i].n)//其插入的位置若能放入左子树(还能放人),往左子树放人,否则走右子树
58 insert(2*i,x,m);
59 else
60 insert(2*i+1,x-b[2*i].n,m);
61 b[i].n--;
62 }
63
64 int main()
65 {
66 int i,j;
67 while(scanf("%d",&n)!=EOF)
68 {
69 for(i=1;i<=n;i++)
70 scanf("%d%d",&a[i].n,&a[i].val);
71 init();
72 for(i=n;i>0;i--)//逆推
73 {
74 insert(1,a[i].n+1,a[i].val);
75 }
76 cout<<ans[1];
77 for(i=2;i<=n;i++)
78 cout<<" "<<ans[i];
79 cout<<endl;
80 }
81 return 0;
82 }
上一篇:poj 2828 Buy Tickets (线段树(排队插入后输出序列))


下一篇:poj 2828 Buy Tickets (线段树)