【POJ2828】Buy Tickets(线段树)

题意:有一个输入序列,每次操作要把b[i]插入到第a[i]个,在第a[i]个后面的要后移,问最后序列。

n<=200000

思路:顺序来只能用splay维护

考虑倒序,对于插入到第K个位置,在线段树二分第K个0的位置,类似于主席树

将其插入后将这个位置修改为已经有数

单点修改

 1 var t:array[1..1000000]of longint;
 2     a,b,c:array[1..300000]of longint;
 3     n,i,k:longint;
 4
 5 procedure pushup(p:longint);
 6 begin
 7  t[p]:=t[p<<1]+t[p<<1+1];
 8 end;
 9
10 function query(l,r,k,p:longint):longint;
11 var mid:longint;
12 begin
13  if l=r then exit(l);
14  mid:=(l+r)>>1;
15  if t[p<<1]>=k then exit(query(l,mid,k,p<<1))
16   else exit(query(mid+1,r,k-t[p<<1],p<<1+1));
17  pushup(p);
18 end;
19
20 procedure update(l,r,k,p:longint);
21 var mid:longint;
22 begin
23  if (l=k)and(r=k) then
24  begin
25   dec(t[p]); exit;
26  end;
27  mid:=(l+r)>>1;
28  if k<=mid then update(l,mid,k,p<<1)
29   else update(mid+1,r,k,p<<1+1);
30  pushup(p);
31 end;
32
33 procedure build(l,r,p:longint);
34 var mid:longint;
35 begin
36  if l=r then
37  begin
38   t[p]:=1; exit;
39  end;
40  mid:=(l+r)>>1;
41  build(l,mid,p<<1);
42  build(mid+1,r,p<<1+1);
43  pushup(p);
44 end;
45
46 begin
47  assign(input,‘poj2828.in‘); reset(input);
48  assign(output,‘poj2828.out‘); rewrite(output);
49  while not eof do
50  begin
51   readln(n);
52   if n=0 then break;
53   for i:=1 to n<<2 do t[i]:=0;
54   fillchar(c,sizeof(c),0);
55   for i:=1 to n do
56   begin
57    read(a[i],b[i]);
58    inc(a[i]);
59   end;
60   build(1,n,1);
61   for i:=n downto 1 do
62   begin
63    k:=query(1,n,a[i],1);
64    c[k]:=b[i];
65    update(1,n,k,1);
66   end;
67   for i:=1 to n-1 do write(c[i],‘ ‘);
68   write(c[n]);
69   writeln;
70  end;
71
72  close(input);
73  close(output);
74 end.
时间: 2024-12-19 21:13:53

【POJ2828】Buy Tickets(线段树)的相关文章

poj-----(2828)Buy Tickets(线段树单点更新)

Buy Tickets Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 12930   Accepted: 6412 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

poj2828 Buy Tickets (线段树 插队问题)

Buy Tickets Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 22097   Accepted: 10834 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 w

[POJ2828]Buy Tickets(线段树,单点更新,二分,逆序)

题目链接:http://poj.org/problem?id=2828 由于最后一个人的位置一定是不会变的,所以我们倒着做,先插入最后一个人. 我们每次处理的时候,由于已经知道了这个人的位置k,这个位置表明,在他之前一定有k个空位,于是将他插在第k+1个位置上.我们可以在线段树上直接二分,根据这个位置,假如这个位置在左子树上,那么一直向左走,否则要减掉左子树剩下的位置后再向右边走,同时更新沿途非叶节点的空闲位置数量(减一),手工画一下图就知道了. 1 /* 2 ━━━━━┒ギリギリ♂ eye!

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),如果使用一般方法插入操作

【poj2828】Buy Tickets 线段树 插队问题

[poj2828]Buy Tickets 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 was approaching, but unluckily the Little Cat still had schedules going here

POJ 2828 Buy Tickets(线段树单点)

https://vjudge.net/problem/POJ-2828 题目意思:有n个数,进行n次操作,每次操作有两个数pos, ans.pos的意思是把ans放到第pos 位置的后面,pos后面的数就往后推一位.最后输出每个位置的ans. 思路:根据题 目可知,最后插入的位置的数才是最终不变的数,所以可以从最后的输入作第1个放入,依此类推,倒插入.在插入时也有一定的技术,首先创建一棵空线段树时,每个节点记录当前范围内有多少个空位置.在插入时,要注意,一个数放入之后那么这个位置就不用管了,那么

POJ 2828 Buy Tickets (线段树 or 树状数组+二分)

题目链接:http://poj.org/problem?id=2828 题意就是给你n个人,然后每个人按顺序插队,问你最终的顺序是怎么样的. 反过来做就很容易了,从最后一个人开始推,最后一个人位置很容易就确定了,那最后第二个人的位置也可以推(与最后一个人的位置无关)...依次就都可以确定所有的人了. 用前缀和的思想,要是这个人的位置确定了,那么就标记这个人位置的值为0,然后回溯更新,跟求逆序对个数的思想比较类似. 线段树: 1 #include <iostream> 2 #include &l

POJ 2828 Buy Tickets(线段树&#183;插队)

题意  n个人排队  每个人都有个属性值  依次输入n个pos[i]  val[i]  表示第i个人直接插到当前第pos[i]个人后面  他的属性值为val[i]  要求最后依次输出队中各个人的属性值 从头到尾看的话  队列是动态的   无法操作  但是反过来看时  pos[i]就可以表示第i个人前面还有多少个人了  然后想到了用线段树做就简单了  线段树维护对应区间还有多少个空位  每次把i放到前面刚好有pos[i]个空位的位置就行了  具体看代码 #include <cstdio> #de

POJ 2828 Buy Tickets | 线段树的喵用

题意: 给你n次插队操作,每次两个数,pos,w,意为在pos后插入一个权值为w的数; 最后输出1~n的权值 题解: 首先可以发现,最后一次插入的位置是准确的位置 所以这个就变成了若干个子问题, 所以用线段树维护一下每个区间剩余多少位置可选 对于一个pos 如果左儿子的剩余超过当前位置,就递归进左子树 反之就相当于留出了左儿子剩余的位置,递归进右子树,当前位置变成pos-左儿子剩余位置 请注意是在后面插入 1 #include<cstdio> 2 #include<algorithm&g