先说说线段树版的POJ2828吧。
这道题让我调试了很长时间,最后才发现原来出现了一个很隐蔽的小问题上。。。。。。
这道题的题目意思很简单,就是一个队列,每个人都不停地插队,让你求出最后的队列是什么。
典型的逆向思维的题目,如果对线段树理解不深刻的话,很难想到用线段树实现,我们不是从前往后插入线段,而是倒序插入线段。
因为最后一个人一定在他想在的位置上,然后插入这个点,同时把这个点所在的线段记录的数-1来表示这个位置已经被占领过,因此下一个人想要进入这个位置的话,只能在后面插入。
program POJ2828;
const MaxN=200001;
type tre=record
l,r,lc,rc,data:longint;
end;
type atp=record
num,val:longint;
end;
var
root,tot,n,i:longint;
ans:array [0..MaxN] of longint;
tree:array [0..MaxN*4] of tre;
a:array [0..MaxN] of atp;
procedure build(var t:longint;l,r:longint);
begin
inc(tot);
t:=tot;
tree[t].l:=l;
tree[t].r:=r;
tree[t].data:=r-l+1;//data域记录这个区间所含点的数目
if l<r then
begin
build(tree[t].lc,l,(l+r) div 2);
build(tree[t].rc,((l+r) div 2)+1,r);
end;
end;
procedure qsort(l,r:longint);//用快排是为了让元素在线段树中的位置有序
var
i,j,m:longint;
t:atp;
begin
i:=l;
j:=r;
m:=a[(l+r) shr 1].num;
repeat
while a[i].num<m do inc(i);
while a[j].num>m do dec(j);
if i<=j then
begin
t:=a[i];
a[i]:=a[j];
a[j]:=t;
inc(i);
dec(j);
end;
until i>j;
if i<r then qsort(i,r);
if l<j then qsort(l,j);
end;
procedure del(t,c,p:longint);
begin
if tree[t].l=tree[t].r then//位置在线段树中的位置随之确定,同时将这段区间的元素置0,即这个点已被占领
begin
a[p].num:=tree[t].l;//该点在最后队列中的位置也确定
tree[t].data:=0;
exit;
end;
if c<=tree[tree[t].lc].data then del(tree[t].lc,c,p) else del(tree[t].rc,c-tree[tree[t].lc].data,p);//小于向左,大于向右,同时注意相减
dec(tree[t].data);//递归减,将这个点之前覆盖过的区间的点的数都-1,即在区间中去掉了要插入的点
end;
begin
assign(input,'POJ2828.in'); reset(input);
assign(output,'POJ2828.out'); rewrite(output);
while not eof do
begin
root:=0;
tot:=0;
readln(n);
for i:=1 to n do readln(a[i].num,a[i].val);
build(root,1,n);
for i:=n downto 1 do del(root,a[i].num+1,i);//注意这里是a[i].num+1,因为建树的时候是从1~n建的,而题目中有0的存在
qsort(1,n);
for i:=1 to n do write(a[i].val,' ');
writeln;
end;
close(input); close(output);
end.