POJ 2828 (线段树 单点更新) Buy Tickets
倒着插,倒着插,这道题是倒着插!
想一下如果 Posi 里面有若干个0,那么排在最前面的一定是最后一个0.
从后往前看,对于第i个数,就应该插在第Posi + 1个空位上,所以用线段树来维护区间空位的个数。
说一下那个坑爹的第56行的判断:
if(i > 1) printf(" ");
将输出的n个数用空格隔开,我感觉这是一个还算常用的写法啊,结果各种莫名TLE,加上输入挂也补救不回来。
去掉这个无谓的判断后,3594MS险过,加上输入挂3094MS,还算是起到了一定的加速作用。
1 #include <cstdio> 2 #include <ctype.h> 3 4 const int maxn = 200000 + 10; 5 6 int n, p[maxn], v[maxn], a[maxn]; 7 int sum[maxn << 2]; 8 9 inline int Scan() 10 { 11 char c = getchar(); 12 while(!isdigit(c)) c = getchar(); 13 14 int x = 0; 15 while(isdigit(c)) { 16 x = x * 10 + c - '0'; 17 c = getchar(); 18 } 19 return x; 20 } 21 22 void build(int o, int L, int R) 23 { 24 if(L == R) { sum[o] = 1; return; } 25 int M = (L + R) / 2; 26 build(o<<1, L, M); 27 build(o<<1|1, M+1, R); 28 sum[o] = sum[o<<1] + sum[o<<1|1]; 29 } 30 31 void update(int o, int L, int R, int p, int v) 32 { 33 if(L == R) { sum[o] = 0; a[L] = v; return; } 34 int M = (L + R) / 2; 35 if(sum[o<<1] >= p) update(o<<1, L, M, p, v); 36 else update(o<<1|1, M+1, R, p-sum[o<<1], v); 37 sum[o] = sum[o<<1] + sum[o<<1|1]; 38 } 39 40 int main() 41 { 42 //freopen("in.txt", "r", stdin); 43 44 while(scanf("%d", &n) == 1) 45 { 46 build(1, 1, n); 47 for(int i = 0; i < n; i++) 48 { 49 p[i] = Scan(); 50 v[i] = Scan(); 51 } 52 for(int i = n - 1; i >= 0; i--) update(1, 1, n, p[i]+1, v[i]); 53 printf("%d", a[1]); 54 for(int i = 2; i <= n; i++) 55 { 56 //if(i > 1) printf(" "); 57 printf(" %d", a[i]); 58 } 59 printf("\n"); 60 } 61 62 return 0; 63 }