链接:http://poj.org/problem?id=2828
题意:n个人排队,每个人有一个权值,给出他们插队的位置,求最后的顺序,按顺序输出权值。
思路:看到这题目,我想这货和线段树什么关系啊,这货怎么能用线段树来做呢。诶,大千世界无奇不有,线段树就是这么的神奇,叹叹!!!闲话少说,走起。
逆着想,最后一个人插队后, 他的位置就是确定了下来的。倒数第二个人插的话,位置在最后一个的前面,最后一个对他无影响,位置在最后一个后面,则最后一个对他有影响,他必须往后移一位。
线段树叶子节点保存的是这个位置上的空位数,初始化为1,如果这个位置上有了一个数,那么减一。但是我不明白在查找的时候,为什么用当前人要插入的位置和空位数进行比较,这个位置可以理解为空位数么???求指点。
#include<cstdio> #include<algorithm> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 const int maxn=200005; int sum[maxn<<2]; int ans[maxn],pos[maxn],val[maxn]; void PushUP(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void build(int l,int r,int rt) { if(l==r) { sum[rt]=1; return; } int m=(l+r)/2; build(lson); build(rson); PushUP(rt); } void query(int p,int v,int l,int r,int rt) { if(l==r) { sum[rt]-=1; ans[r]=v; return; } int m=(l+r)/2; if(p<=sum[rt<<1]) query(p,v,lson);//不明白 else query(p-sum[rt<<1],v,rson); PushUP(rt); } int main() { int n; while(~scanf("%d",&n)) { build(1,n,1); for(int i=0;i<n;i++) scanf("%d%d",&pos[i],&val[i]); for(int i=n-1;i>=0;i--) query(pos[i]+1,val[i],1,n,1); for(int i=1;i<=n;i++) printf("%d ",ans[i]); printf(" "); } return 0; }
这题也可以用树状数组写,后面再贴上来。