链接
https://codeforces.com/contest/1175/problem/E
题解
用
f
i
,
k
f_{i,k}
fi,k表示从坐标为
i
i
i的点(借助线段)往左跳
2
k
2^k
2k次能到达的坐标最小的位置
先把线段按照左端点排序,用一个指针搞一搞,处理出
f
i
,
0
f_{i,0}
fi,0
然后倍增算出
f
i
,
1...20
f_{i,1...20}
fi,1...20
查询
(
x
,
y
)
(x,y)
(x,y)就是二分跳几次,每次用记录的信息合成,看一下从
y
y
y往左跳
m
i
d
mid
mid次能不能跳到
≤
l
\leq l
≤l的位置
时间复杂度
O
(
n
l
o
g
n
+
m
l
o
g
2
L
)
O(nlogn+mlog^2L)
O(nlogn+mlog2L)
L
L
L是横坐标的范围
代码
#include<bits/stdc++.h>
#define maxn 300010
#define maxk 20
#define linf (1ll<<60)
#define iinf 0x3f3f3f3f
#define eps 1e-8
#define cl(x) memset(x,0,sizeof(x))
#define mod 1000000007ll
using namespace std;
int read(int x=0)
{
int c, f=1;
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
for(;isdigit(c);c=getchar())x=x*10+c-48;
return f*x;
}
int f[500010][20], N, M;
pair<int,int> seg[maxn];
int check(int pos, int step)
{
int k=0, now=pos;
for(;step;step>>=1,k++)if(step&1)now=f[now][k];
return now;
}
int main()
{
int i, j, k, p, x, y, ans, pos;
N=read(), M=read();
for(i=1;i<=N;i++)
{
seg[i].first=read();
seg[i].second=read();
}
sort(seg+1,seg+N+1);
for(i=0;i<=500000;i++)f[i][0]=i;
p=0;
for(i=1;i<=N;i++)
{
while(p<seg[i].first)p++;
while(p<=seg[i].second)
{
f[p][0]=min(f[p][0],seg[i].first);
p++;
}
}
for(k=1;k<maxk;k++)
{
for(i=0;i<=500000;i++)
{
f[i][k]=f[f[i][k-1]][k-1];
}
}
while(M--)
{
x=read(), y=read();
if(f[y][maxk-1]>x)
{
printf("-1\n");
continue;
}
int l(0), r(N), mid(l+r>>1);
while(l<r)
{
if(check(y,mid)<=x)r=mid;
else l=mid+1;
mid=l+r>>1;
}
printf("%d\n",l);
}
return 0;
}