POJ-2828 Buy Tickets---线段树+逆序

题目链接:

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

题目大意:

插队的问题,每个案例给出n,代表有n个插队的,每个给出p,v,意思是代号为v的人插在了第p个人的后面,问最后的队伍的排列?

解题思路:

如果从前往后递推,每次插入在前面的话,后面的人都需要往后移动,所以考虑从后往前放

从后往前退的话每次可以推到确定的位置,插入在位置为i的地方,说明按从前往后放的时候前面有i个人,从后往前放的话就是前面有i个空格,放在第i+1个空格的地方,这样逆序放的话每次都可以放在确定的位置,不用移动。

线段树存的是区间内空格的数目,每次放的时候,位置需要加1,因为位置i说明放在前面有i个空格,该点在第i+1个空格处。

 1 #include<iostream>
 2 #include<cstdio>
 3 #define MID(l, r) (l + (r - l) / 2)
 4 #define lson(o) (o * 2)
 5 #define rson(o) (o * 2 + 1)
 6 using namespace std;
 7 typedef long long ll;
 8 const int INF = 1e9 +7;
 9 const int maxn = 1e6 + 10;
10 int  h, w, n;
11 struct node
12 {
13     int l, r, sum;
14 }tree[maxn];
15 int ans[maxn];
16 void build(int o, int l, int r)
17 {
18     tree[o].l = l, tree[o].r = r;
19     if(l == r)
20     {
21         tree[o].sum = 1;
22         return;
23     }
24     int m = MID(l, r);
25     int lc = lson(o), rc = rson(o);
26     build(lc, l, m);
27     build(rc, m + 1, r);
28     tree[o].sum = tree[lc].sum + tree[rc].sum;
29 }
30 void insert(int o, int a, int b)//a个空位
31 {
32     if(tree[o].l == tree[o].r)
33     {
34         ans[tree[o].l] = b;
35         tree[o].sum = 0;
36         return;
37     }
38     int lc = lson(o), rc = rson(o);
39     if(a <= tree[lc].sum)insert(lc, a, b);//空位数目小于等于左子树,在左子树中插入
40     else insert(rc, a - tree[lc].sum, b);//空位数目大于左子树,在右子树插入,此时a需要减去左子树的空位数目
41     tree[o].sum = tree[lc].sum + tree[rc].sum;//在插如之后空位数目发生变化,需要维护本节点的sum值
42 }
43 int a[maxn], b[maxn];
44 int main()
45 {
46     int n, m;
47     while(scanf("%d", &n) != EOF)
48     {
49         build(1, 1, n);
50         for(int i = 0; i < n; i++)scanf("%d%d", &a[i], &b[i]), a[i]++;//空位数目自加一,表示自己在第a[i]个空位处
51         for(int i = n - 1; i >= 0; i--)
52         {
53             insert(1, a[i], b[i]);
54         }
55         for(int i = 1; i < n; i++)printf("%d ", ans[i]);
56         printf("%d\n", ans[n]);
57 
58     }
59     return 0;
60 }

 

posted @ 2018-05-11 22:23  _努力努力再努力x  阅读(151)  评论(0编辑  收藏  举报