题目链接:http://poj.org/problem?id=2828
插队问题,看样例看hits就能理解题意。
难点在于:N≤200,000。插入数据从后往前,线段树节点维护当前空位置数量。
比如第一个样例:
4 0 77 1 51 1 33 2 69
倒着插入,位置分别+1。首先是3 69。在位置3处插入后,此时位置3的父节点[3,4]显示还有1个位置,同层的节点[1,2]显示有两个。此时树根节点[1,4]显示有3个空位。
再插入2 33。插入位置为2。此时树根节点[1,4]显示有2个空位,[1,2]有1个,[3,4]有一个。
问题来了,插入2 51的时候如何调整:因为是倒着插入数据的,那么也就是之前插入的未发生冲突的数字位置是确定不会再移动。下面遇到了需要调整的部分:
因为被后来的人插了队,所以这个节点应该向后错一个位置。所以被调整到了位置4。同理1 77。
1 #include <algorithm> 2 #include <iostream> 3 #include <iomanip> 4 #include <cstring> 5 #include <climits> 6 #include <complex> 7 #include <fstream> 8 #include <cassert> 9 #include <cstdio> 10 #include <cstdlib> 11 #include <bitset> 12 #include <vector> 13 #include <deque> 14 #include <queue> 15 #include <stack> 16 #include <ctime> 17 #include <set> 18 #include <map> 19 #include <cmath> 20 21 using namespace std; 22 23 #define lson l, m, rt << 1 24 #define rson m + 1, r, rt << 1 | 1 25 const int maxn = 222222; 26 int st[maxn<<2]; 27 int pos[maxn], num[maxn], ans[maxn]; 28 29 void pushUP(int rt) { 30 st[rt] = max(st[rt<<1], st[rt<<1|1]); 31 } 32 33 void build(int l, int r, int rt) { 34 st[rt] = r - l + 1; 35 if(l == r) { 36 return; 37 } 38 int m = (l + r) >> 1; 39 build(lson); 40 build(rson); 41 } 42 43 void update(int p, int l, int r, int rt, int& id) { 44 st[rt]--; 45 if(l == r) { 46 id = l; 47 return; 48 } 49 int m = (l + r) >> 1; 50 if(st[rt<<1] >= p) { 51 update(p, lson, id); 52 } 53 else { 54 p -= st[rt<<1]; 55 update(p, rson, id); 56 } 57 } 58 59 int main() { 60 // freopen("in", "r", stdin); 61 int n; 62 while(~scanf("%d", &n)) { 63 build(1, n, 1); 64 for(int i = 1; i <= n; i++) { 65 scanf("%d %d", &pos[i], &num[i]); 66 } 67 int id = 0; 68 for(int i = n; i >= 1; i--) { 69 update(pos[i]+1, 1, n, 1, id); 70 ans[id] = num[i]; 71 } 72 for(int i = 1; i <= n; i++) { 73 printf("%d ", ans[i]); 74 } 75 printf("\n"); 76 } 77 return 0; 78 }