题目
Input
第一行包括两个正整数,N ,M ,分别表示线段树的宽以及询问次数。
以下N-1 行以先序遍历(dfs深搜顺序)描述一个小R线段树,每行一个正整数表示当前非叶子节点的 mid,保证每个节点L<=mid<=r 。
(因为叶子节点不需要mid ,所以在读入时走到叶子节点时回溯即可,所以共N-1 个mid ,而且保证1~N-1 各出现一次)
而后M 行每行包括两个正整数,L,r(1<=L<=r<=N) 描述一个要求区间定位的区间。
Output
M行每行包括一个正整数,表示给出的询问区间在给定的线段树上的区间定位个数。
Sample Input
7 3
4
3
1
2
5
6
3 6
2 7
1 6
Sample Output
4
3
3
【样例解释】
Data Constraint
比赛时の想法
比赛的时候思考了一会儿,然后想到了贪心,每一次左端点都尽可能往右跳,那么答案肯定是最优的,但是只有75分,并没有想到可以用倍增优化(其实想到了也打不出来)
正解
第一种是上述的贪心+倍增优化(好难打啊打不出来)
第二种我们需要先发现一个性质:
区间定位个数(答案) = 2 * 区间长度 - 完全被该区间包含的节点个数。
如果查询的区间为[l,r],那我们其实是查询所有完全在区间线段
那么就直接用二维偏序计数的思想解决问题(第一位排序,第二位用个线段树什么的)
贴代码
var
tree:array[0..300005]of longint;
i,j,k,l,n,m,tot,total,mid:longint;
a:array[0..200005,1..2]of longint;
b:array[0..200005,1..3]of longint;
ans:array[0..100005]of longint;
procedure maketree(l,r:longint);
var
mid:longint;
begin
if l<>r then
begin
readln(mid);
inc(k);
a[k,1]:=l;
a[k,2]:=mid;
maketree(l,mid);
inc(k);
a[k,1]:=mid+1;
a[k,2]:=r;
maketree(mid+1,r);
end;
end;
procedure qsort(l,r:longint);
var
i,j,mid:longint;
begin
i:=l;
j:=r;
mid:=b[(i+j) div 2,1];
repeat
while b[i,1]>mid do inc(i);
while b[j,1]<mid do dec(j);
if i<=j then
begin
b[0]:=b[i];
b[i]:=b[j];
b[j]:=b[0];
inc(i);
dec(j);
end;
until i>j;
if i<r then qsort(i,r);
if l<j then qsort(l,j);
end;
procedure change(x,l,r,y:longint);
var
mid:longint;
begin
if (l=r) and (l=y) then
tree[x]:=tree[x]+1
else
begin
mid:=(l+r) div 2;
tree[x]:=tree[x]+1;
if y<=mid then change(x*2,l,mid,y) else change(x*2+1,mid+1,r,y);
end;
end;
procedure find(v,l,r,x,y:longint);
var
mid:longint;
begin
if x>y then exit;
if (l=x) and (r=y) then
begin
tot:=tot-tree[v]
end else
begin
mid:=(l+r) div 2;
if y<=mid then find(v*2,l,mid,x,y) else
if x>mid then find(v*2+1,mid+1,r,x,y) else
begin
find(v*2,l,mid,x,mid);
find(v*2+1,mid+1,r,mid+1,y);
end;
end;
end;
begin
// assign(input,'t3.in'); reset(input);
readln(n,m);
k:=1;
a[1,1]:=1;
a[1,2]:=n;
maketree(1,n);
for i:=1 to m do readln(b[i,1],b[i,2]);
for i:=1 to m do b[i,3]:=i;
qsort(1,m);
k:=2*n-1;
for i:=1 to m do
begin
for j:=k downto 1 do
if a[j,1]>=b[i,1] then
begin
change(1,1,n,a[j,2]);
inc(total);
if j=1 then k:=-1;
end else break;
if k=-1 then
begin
k:=0;
j:=0;
end else k:=j;
tot:=total;
find(1,1,n,b[i,2]+1,n);
ans[b[i,3]]:=2*(b[i,2]-b[i,1]+1)-tot;
end;
for i:=1 to m do writeln(ans[i]);
// close(input);
end.