POJ 2828 Buy Tickets(线段树单点)

https://vjudge.net/problem/POJ-2828

题目意思:有n个数,进行n次操作,每次操作有两个数pos, ans。pos的意思是把ans放到第pos 位置的后面,pos后面的数就往后推一位。最后输出每个位置的ans。

    思路:根据题 目可知,最后插入的位置的数才是最终不变的数,所以可以从最后的输入作第1个放入,依此类推,倒插入。在插入时也有一定的技术,首先创建一棵空线段树时,每个节点记录当前范围内有多少个空位置。在插入时,要注意,一个数放入之后那么这个位置就不用管了,那么树中所有的空位置就是余下的数所对应的位置,也就是把余下的数又可以看作是一个新的集合。那么每次插入都是当前集合的第1次放。

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <string>
 4 #include <sstream>
 5 #include <set>
 6 #include <vector>
 7 #include <stack>
 8 #include <map>
 9 #include <queue>
10 #include <deque>
11 #include <cstdlib>
12 #include <cstdio>
13 #include <cstring>
14 #include <cmath>
15 #include <ctime>
16 #include <functional>
17 // #include <bits/stdc++.h>
18 using namespace std;
19 
20 int n,ans[1000000];
21 
22 struct node
23 {
24     int n,val;
25 }a[1000000];
26 
27 struct tree
28 {
29     int l,r,n;
30 }b[1000000];
31 
32 void init()
33 {
34     int i,j,k;
35     for(k=1;k<n;k<<=1);
36     for(i=k;i<2*k;i++)
37     {
38         b[i].l=b[i].r=i-k+1;
39         b[i].n=1;//每个叶子节点只能放入一个人
40     }
41     for(i=k-1;i>0;i--)
42     {
43         b[i].l=b[2*i].l;
44         b[i].r=b[2*i+1].r;
45         b[i].n=b[2*i].n+b[2*i+1].n;//每个区间是其左右子树所能放入的人数总和
46     }
47 }
48 
49 void insert(int i,int x,int m)
50 {
51     if(b[i].l==b[i].r)//找到叶子节点,这个节点存放该人,并且叶子节点能放入的人数清0
52     {
53         ans[b[i].l]=m;
54         b[i].n=0;
55         return;
56     }
57     if(x<=b[2*i].n)//其插入的位置若能放入左子树(还能放人),往左子树放人,否则走右子树
58         insert(2*i,x,m);
59     else
60         insert(2*i+1,x-b[2*i].n,m);
61         b[i].n--;
62 }
63 
64 int main()
65 {
66     int i,j;
67     while(scanf("%d",&n)!=EOF)
68     {
69         for(i=1;i<=n;i++)
70             scanf("%d%d",&a[i].n,&a[i].val);
71         init();
72         for(i=n;i>0;i--)//逆推
73         {
74             insert(1,a[i].n+1,a[i].val);
75         }
76         cout<<ans[1];
77         for(i=2;i<=n;i++)
78             cout<<" "<<ans[i];
79         cout<<endl;
80     }
81     return 0;
82 }

 

转载于:https://www.cnblogs.com/YingZhixin/p/7529269.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值