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 }
越努力,越幸运