poj Buy Tickets

题目链接:http://poj.org/problem?id=2828

类似的题目:http://www.cnblogs.com/lovychen/p/3674048.html

测试数据:

in:

4
0 77
1 51
1 33
2 69
4
0 20523
1 19243
1 3890
0 31492

out:

77 33 69 51
31492 20523 3890 19243

题目分析:直接倒着进行插入,然后按照从前向后寻找空位进行插入:

【题解】:

    线段树节点中保存这一段中的空位数,然后倒序对pos插入:

    例如:  0 77
         1 51
         1 33
         2 69

    先取: 2 69  ——  ——  —69—   ——   (需要前面有3个空位才能插入)

然后取: 1 33   ——   —33—    —69—    ——   (需要前面有2个空位才能插入)

然后取: 1 51   ——   —33—    —69—    —51—   (需要前面有2个空位才能插入)  前面只有1个空位  故插入后面空格

   然后取: 0 77   —77—   —33—    —69—    —51—   (需要前面有1个空位才能插入)

AC代码:

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<queue>
 6 #include<string>
 7 #include<cmath>
 8 using namespace std;
 9 const int N = 200010;
10 int T,tot;
11 int pre[N],vis[N];
12 struct TT
13 {
14     int x,y;
15 }a[N];
16 int lowbit(int x)
17 {
18     return x&(-x);
19 }
20 void init()
21 {
22     for(int i=1;i<=T;i++)
23       vis[i] =lowbit(i);
24 }
25 int sum(int x)
26 {
27     int ans = 0;
28     while(x>0)
29     {
30         ans = ans+vis[x];
31         x = x-lowbit(x);
32     }
33     return ans;
34 }
35 int update(int x)
36 {
37     while(x<=T)
38     {
39         vis[x] = vis[x] - 1;
40         x = x +lowbit(x);
41     }
42 }
43 void add(int x,int y)
44 {
45     int l=1,r=T,mid;
46     while(l<r)
47     {
48         //printf("l === %d %d %d\n",l,r,mid);
49         mid = (l+r)/2;
50         if(sum(mid)>=x) r = mid;
51         else l = mid+1;
52     }
53     //printf("l = %d\n",l);
54     update(l);
55     pre[l] = y;
56 }
57 int main()
58 {
59 int aa,bb;
60   while(~scanf("%d",&T))
61   {
62       init();
63       for(int i=1;i<=T;i++)
64       {
65         scanf("%d %d",&aa,&bb);
66         a[i].x = aa+1;
67         a[i].y = bb;
68       }
69       for(int i=T;i>0;i--)
70           add(a[i].x,a[i].y);
71       for(int i=1;i<=T;i++)
72       {
73             if(i==1) printf("%d",pre[i]);
74             else printf(" %d",pre[i]);
75       }
76       printf("\n");
77   }
78   return 0;
79 }
时间: 2024-11-07 13:59:47

poj Buy Tickets的相关文章

poj 2828 Buy Tickets 【线段树点更新】

题目:poj 2828 Buy Tickets 题意:有n个人排队,每个人有一个价值和要插的位置,然后当要插的位置上有人时所有的人向后移动一位当这个插入到这儿,如果没有直接插进去. 分析:分析发现直接插入移动的话花时间太多,我们可不可以用逆向思维.从后往前来,因为最后一个位置是肯定能确定的,而其他的则插入空的第某个位置. 比如第一组样例: 4 0 77 1 51 1 33 2 69 开始时候位置都为空 编号0 1 2 3 首先从最后一个来2 69 第二个位置空,则可以直接放 然后编号变为0 1

POJ 2828 Buy Tickets(线段树)

Language: Default Buy Tickets Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 13847   Accepted: 6926 Description Railway tickets were difficult to buy around the Lunar New Year in China, so we must get up early and join a long queue- The

poj 2828 Buy Tickets

Buy Tickets Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 13277   Accepted: 6595 Description Railway tickets were difficult to buy around the Lunar New Year in China, so we must get up early and join a long queue- The Lunar New Year wa

POJ 2828 Buy Tickets (线段树)

题目大意: 排队有人插队,每一次都插到第 i 个人的后面. 最后输出顺序. 思路分析: 你会发现,如果反向处理的话,你就知道这个人是第几个了. 那么问题一下子就简化了. 就是在线段树上找第几个空位置就行了. #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <vector> #define lson num<<1

POJ 2828 Buy Tickets 线段树解法

此题应用线段树的方法非常巧妙.没做过真的难想得出是这么想的. 是一个逆向思维的运用. 其实一看到这道题目我就想到要运用逆向思维的了,但是就是没那么容易想通的. 思路: 1 要从后面往前更新线段树 2 线段树记录的是当前区间还剩下多少个记录空间 3 因为后面的插入会使得前面的插入往后退,那么前面插入的下标如果大于前面可以插入的空间,就需要往后退了. 好难理解的操作.仔细观察一下下面update这个函数吧. 二分地去查找适合的插入位置,把插入操作时间效率提高到 O(lgn),如果使用一般方法插入操作

POJ 2827 Buy Tickets(排队问题,线段树应用)

POJ 2827 Buy Tickets(排队问题,线段树应用) ACM 题目地址:POJ 2827 Buy Tickets 题意: 排队买票时候插队. 给出一些数对,分别代表某个人的想要插入的位置Pos_i和他的Val_i,求出最后的队列的val顺序. 分析: 也是一道很巧妙的题目. 刚开始天真的以为sort一下就行了.wa了一发后发现我错了... 原来可以很巧妙的用线段树做.由于某个人想要插入posi位置,插入后他就在posi位置上了,但是可能其他人会插到他前面来,他的位置就会变成[在他后面

线段树(单点更新) POJ 2828 Buy tickets

题目传送门 1 /* 2 结点存储下面有几个空位 3 每次从根结点往下找找到该插入的位置, 4 同时更新每个节点的值 5 */ 6 #include <cstdio> 7 #define lson l, m, rt << 1 8 #define rson m+1, r, rt << 1 | 1 9 10 const int MAX_N = 200000 + 10; 11 int pos[MAX_N], val[MAX_N]; 12 int sum[MAX_N <&

POJ 2828 poj 2828 Buy Tickets 【树状数组,已知前n项和为K,返回n值】

题目链接:http://poj.org/problem?id=2828 在一个队列中,一个人想要插队,告诉你每个新来的人会插在i个人后面,求出最后的队列. 如果我们用模拟的话,那么时间复杂度肯定是超了:想想,如果我们逆序,那么最后来的人的位置一定是固定的,这样的话,我们将问题转化成逆序扫描给出数据,插在i个人后面这个数据就变成了在这个人前面需要留出多少个空位.如此我们只需要用树状数组记录前n项总共有多少个空位,每扫描一个数据,就找出能使得他前面正好有i个空位. 这题用树状数组或者线段树都可以,今

【POJ】Buy Tickets(线段树)

点更新用法很巧妙的一道题.倒序很容易的找到该人的位置,而update操作中需要不断的变化下标才能合理的插入.看了别人写的代码,学习了. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <map> 5 using namespace std; 6 7 const int maxn = 2e5 + 10; 8 int sumv[maxn << 2],