SYSU-5, POJ 2131, 树状数组+二分
Posted 茶杯
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SYSU-5, POJ 2131, 树状数组+二分相关的知识,希望对你有一定的参考价值。
题目大意:给出n个人,顺序对位置进行请求,如果第i个人请求的位置上有人,则让这个人顺延,如果顺延的位置继续有人,递归进行,问最后所有人的位置。
解:这题貌似可以用平衡树+并查集搞定,但是我队友强烈安利树状数组的做法。赛场上没出,赛后结合discuz想了一下,作一下处理。
首先如果是一个请求第a[i]个有空位置的问题,那么这个问题显然可以用树状数组维护前缀和即可。所以我们现在考虑将原问题转化成这个问题。
考虑终态,把没有人的位置去掉,剩下的n个座位排在一起,显然转化成上面模型的形式
第i个询问时,如果我们记b[i] = 前i-1个询问里1~a[i]-1上有多少座位被请求,那么显然倒过来处理时,b[i]+1个位置即为所求位置(因为前面的人不会和后面的人抢位置,后面的人更优先确定,所以他的位置只取决于前面有多少空的,而他占掉座位后,如果前面的人请求了原意义上的同一位置,那么就在转化后的位置顺延即可,其实就是我们所提希望的转化模型,n个椅子,每次请求第b[i]个空椅子)
但是平衡树的做法真的很快(毕竟省一个二分的log),10s的时限我写了9.8s = =b,如果写完计算几何还有力气就琢磨一下平衡树的写法吧!
1 #include <cstdio> 2 #include <string> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #include <cstring> 7 #include <complex> 8 #include <set> 9 #include <vector> 10 #include <map> 11 #include <queue> 12 #include <deque> 13 #include <ctime> 14 15 using namespace std; 16 17 const double EPS = 1e-8; 18 19 #define ABS(x) ((x)<0?(-(x)):(x)) 20 #define SQR(x) ((x)*(x)) 21 #define MIN(a,b) ((a)<(b)?(a):(b)) 22 #define MAX(a,b) ((a)>(b)?(a):(b)) 23 24 #define LSON(x) ((x)<<1) 25 #define RSON(x) (((x)<<1)+1) 26 #define LOWBIT(x) ((x)&(-(x))) 27 #define MAXN 311111 28 #define LL long long 29 #define OO 214748364 30 31 int a[MAXN], b[MAXN], f[MAXN], fa[MAXN]; 32 int n, m; 33 34 struct TreeArray{ 35 int tree[MAXN], n; 36 void clear(int lim = MAXN-10) { 37 memset(tree, 0, sizeof(tree[0])*(lim+10)); 38 n = lim; 39 } 40 void add(int x, int num) { 41 while (x <= n) { 42 tree[x] += num; 43 x += LOWBIT(x); 44 } 45 } 46 int get(int x) { 47 int res = 0; 48 while (x) { 49 res += tree[x]; 50 x -= LOWBIT(x); 51 } 52 return res; 53 } 54 } treeArray; 55 56 int get(int x) { 57 // return x == fa[x] ? x : fa[x] = get(fa[x]); 58 int t = x; while (t != fa[t]) t = fa[t]; 59 for (int i = x, j; i != t; i = j) { 60 j = fa[x]; fa[x] = t; 61 } 62 return t; 63 } 64 65 int main() { 66 freopen("test.txt", "r", stdin); 67 scanf("%d%d", &n, &m); 68 treeArray.clear(n+m); 69 for (int i = 1; i <= n+m; ++i) fa[i] = i; 70 for (int i = 1; i <= n; ++i) { 71 scanf("%d", a+i); 72 int t = get(a[i]); ++f[t]; 73 b[i] = treeArray.get(a[i]-1); 74 treeArray.add(t, 1); 75 fa[t] = t + 1; 76 } 77 78 treeArray.clear(n+m); 79 for (int i = 1; i <= n+m; ++i) { 80 if (f[i] == 0) continue; 81 treeArray.add(i, 1); 82 } 83 84 memset(a, 0, sizeof(a)); 85 for (int i = n; i; --i) { 86 int l = 1, r = n+m, mid, t; 87 while (l <= r) { 88 mid = (l+r)>>1; 89 if ((t = treeArray.get(mid)) == b[i]+1 && f[mid] == 1) { 90 treeArray.add(mid, -1); f[mid] = 0; 91 a[mid] = i; break; 92 } else if (t < b[i]+1) { 93 l = mid + 1; 94 } else { 95 r = mid - 1; 96 } 97 } 98 } 99 for (int i = MAXN-1; i; --i) if (a[i]) { 100 printf("%d\\n", i); 101 for (int j = 1; j <= i; ++j) printf("%d%c", a[j], j == i ? \'\\n\' : \' \'); 102 break; 103 } 104 105 return 0; 106 }
以上是关于SYSU-5, POJ 2131, 树状数组+二分的主要内容,如果未能解决你的问题,请参考以下文章