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 }

 

posted on 2015-08-25 17:15  蜘蛛侦探  阅读(259)  评论(0编辑  收藏  举报