http://poj.org/problem?id=2828
插队问题,n个人,下面n行每行a,b表示这个人插在第a个人的后面和这个人的编号为b,最后输出队伍的情况
涉及到节点的问题可以用到线段树,这里因为每个人插队时有顺序的,如果按照正着的顺序来情况太复杂,所以可以试试倒过来,从最后一个人开始,此时找到的位置
一定是最终位置,这样就很简单了, 结构体中多开一个mark表示每个区间的空位置,多开一个sum表示人的编号
这道题不错,提醒我们有时候换一换思路,逆向思考一下
1 #include<cstdio> 2 using namespace std; 3 struct point { 4 int l,r; 5 int sum,mark; 6 }; 7 point tree[200001*4]; 8 int a[200001],b[200001]; 9 void build(int i,int left,int right) 10 { 11 tree[i].l=left,tree[i].r=right; 12 tree[i].mark=(tree[i].r-tree[i].l)+1; 13 tree[i].sum=0; 14 if (right==left) return; 15 int mid=(left+right)/2; 16 build(i*2,left,mid); 17 build(i*2+1,mid+1,right); 18 } 19 void update(int i,int pos,int val) 20 { 21 if (tree[i].l==tree[i].r) 22 { 23 tree[i].sum=val; 24 tree[i].mark--; 25 return ; 26 } 27 if (pos<=tree[i*2].mark) 28 update(i*2,pos,val); 29 else 30 update(i*2+1,pos-tree[i*2].mark,val); 31 tree[i].mark=tree[i*2].mark+tree[i*2+1].mark; //更新区间的空位 32 } 33 void check(int i) 34 { 35 if (tree[i].l==tree[i].r) 36 { 37 printf("%d ",tree[i].sum); 38 return ; 39 } 40 check(i*2); 41 check(i*2+1); 42 } 43 int main() 44 { 45 int n,i; 46 while (~scanf("%d",&n)) 47 { 48 for (i=1;i<=n;i++) 49 scanf("%d %d",&a[i],&b[i]); 50 build(1,1,n); 51 for (i=n;i>0;i--) 52 update(1,a[i]+1,b[i]); 53 check(1); 54 printf("\n"); 55 } 56 return 0; 57 }