题目大意
给了你 n(1<=n<=2*10^5) 个人的插队信息,让你输出最终的队列的排列
做法分析
正向思考的话,这道题就是最简单的模拟了,明显不能这样做
那就逆向思考吧
现在我们知道总共有 n 个人,且最后一个人要排在这 n 个人中的位置是 p[n],我们可以直接把队列的第 p[n] 个位子安排给第 n 个人
现在来考虑第 n-1 个人,他要排在只有 n-1 个人的第 p[n-1] 个位置上,怎么做呢?我们肯定是从队列的第 1 个开始数,遇到没有被人占领的位置就加 1,直到数到了 p[n-1],那么这个空位就安排给第 n-1 个人
对于第 n-2 个人,以及剩下的所有人都可以这样做
当然,不可能真的一个一个的数,但是可以用线段树动态的统计空余位置的数量和更新空余位置的信息
所以对每个人安排位置,最坏需要 log(n) 的时间,总的时间复杂度是 nlog(n) 的
搞不懂 POJ 的 G++ 和 C++ 有什么区别,用 G++ 交老是 TLE,但手抖了一下用 C++ 交了一发,竟然快速的通过了
参考代码
POJ 2828
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 5 using namespace std; 6 7 const int N=200006; 8 9 struct interval_tree 10 { 11 struct data 12 { 13 int st, en, val; 14 }T[N<<2]; 15 16 void build(int id, int L, int R) 17 { 18 T[id].st=L, T[id].en=R, T[id].val=R-L+1; 19 if(L==R) return; 20 int mid=(L+R)>>1; 21 build(id<<1, L, mid); 22 build(id<<1|1, mid+1, R); 23 } 24 25 int query(int id, int pos) 26 { 27 T[id].val--; 28 if(T[id].st==T[id].en) return T[id].st; 29 if(pos<=T[id<<1].val) return query(id<<1, pos); 30 else return query(id<<1|1, pos-T[id<<1].val); 31 } 32 } tree; 33 34 int ans[N], temp[N][2]; 35 36 int main() 37 { 38 int n; 39 while(scanf("%d", &n)!=EOF) 40 { 41 for(int i=0; i<n; i++) scanf("%d%d", &temp[i][0], &temp[i][1]); 42 tree.build(1, 1, n); 43 for(int i=n-1; i>=0; i--) ans[tree.query(1, temp[i][0]+1)]=temp[i][1]; 44 for(int i=1; i<=n; i++) 45 { 46 printf("%d", ans[i]); 47 if(i==n) printf("\n"); 48 else printf(" "); 49 } 50 } 51 return 0; 52 }