点击打开poj 2828
思路: 树状数组/线段树单点更新
分析:
1 题目给定n个人的位置pos和id,要我们求出最后n个人的位置
2 我们先来考虑朴素的算法,假设现在进来一个人那么我们把它放到pos的位置,那么pos之后的所有的人都要向后移动一位,那么n个人的话最坏的情况是O(n^2),很显然时间效率上面是不行的
3 由于正向的插入不行,那么我们考虑反向插入的情况(就像逆向的并查集),那么我们可以马上知道第n个人的位置,那么第n-1个人的位置是基于第n个人的。假设第i个人的要插入pos的位置,那么这个时候我们只要把第i个放到第pos个空的位置即可(可以自己手动模拟一遍),那么我们维护空位置可以利用树状数组和线段树来维护
代码:
线段树
/************************************************ * By: chenguolin * * Date: 2013-09-08 * * Address: http://blog.csdn.net/chenguolinblog * ************************************************/ #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define Lson(x) (x<<1) #define Rson(x) (Lson(x)|1) #define Mid(x,y) ((x+y)>>1) #define Sum(x,y) (x+y) const int MAXN = 200010; struct Node{ int left; int right; int sum; }; Node node[4*MAXN]; struct Edge{ int pos; int val; }; Edge e[MAXN]; int n , ans[MAXN]; void push_up(int pos){ node[pos].sum = node[Lson(pos)].sum+node[Rson(pos)].sum; } void buildTree(int left , int right , int pos){ node[pos].left = left; node[pos].right = right; node[pos].sum = right-left+1; if(left == right) return; int mid = Mid(left , right); buildTree(left , mid , Lson(pos)); buildTree(mid+1 , right , Rson(pos)); } void update(int index , int pos){ if(node[pos].left == node[pos].right){ node[pos].sum--; return; } int mid = Mid(node[pos].left , node[pos].right); if(index <= mid) update(index , Lson(pos)); else update(index , Rson(pos)); push_up(pos); } int query(int x , int pos){ if(node[pos].left == node[pos].right) return node[pos].left; if(node[Lson(pos)].sum >= x) return query(x , Lson(pos)); else return query(x-node[Lson(pos)].sum , Rson(pos)); } void solve(){ buildTree(1 , n , 1); for(int i = n ; i >= 1 ; i--){ int pos = e[i].pos; int id = query(pos , 1); ans[id] = e[i].val; update(id , 1); } printf("%d" , ans[1]); for(int i = 2 ; i <= n ; i++) printf(" %d" , ans[i]); puts(""); } int main(){ while(scanf("%d" , &n) != EOF){ for(int i = 1 ; i <= n ; i++){ scanf("%d%d" , &e[i].pos , &e[i].val); e[i].pos++; } solve(); } return 0; }
树状数组
/************************************************ * By: chenguolin * * Date: 2013-09-08 * * Address: http://blog.csdn.net/chenguolinblog * ************************************************/ #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define Lson(x) (x<<1) #define Rson(x) (Lson(x)|1) #define Mid(x,y) ((x+y)>>1) #define Sum(x,y) (x+y) const int MAXN = 200010; struct Node{ int pos; int val; }; Node node[MAXN]; int ans[MAXN]; int n , treeNum[MAXN]; int lowbit(int x){ return x&(-x); } int getSum(int x){ int sum = 0; while(x){ sum += treeNum[x]; x -= lowbit(x); } return sum; } void add(int x , int val){ while(x < MAXN){ treeNum[x] += val; x += lowbit(x); } } int search(int x){ int left = 1; int right = n; while(left <= right){ int mid = Mid(left , right); int sum = getSum(mid); if(sum < x) left = mid+1; else right = mid-1; } return left; } void solve(){ for(int i = 1 ; i <= n ; i++) add(i , 1); ans[node[n].pos] = node[n].val; add(node[n].pos , -1); for(int i = n-1 ; i >= 1 ; i--){ int pos = node[i].pos; int id = search(pos); ans[id] = node[i].val; add(id , -1); } printf("%d" , ans[1]); for(int i = 2 ; i <= n ; i++) printf(" %d" , ans[i]); puts(""); } int main(){ while(scanf("%d" , &n) != EOF){ for(int i = 1 ; i <= n ; i++){ scanf("%d%d" , &node[i].pos , &node[i].val); node[i].pos++; } solve(); } return 0; }