CF793F Julia the snail
题目
首先我们考虑暴力
因为
r
r
r 互不相同,所以记
f
r
o
m
[
r
]
=
l
from[r]=l
from[r]=l。对于每个
(
x
,
y
)
(x,y)
(x,y) 的询问,我们记一个区间
[
l
,
r
]
[l,r]
[l,r] 表示这个区间内的所有点我们都可以到达。最初为
[
x
,
以
x
为左端点的线段的最大右端点
]
[x,\text{以}\space x\space\text{为左端点的线段的最大右端点}]
[x,以 x 为左端点的线段的最大右端点]。然后从小到大枚举
[
x
+
1
,
y
]
[x+1,y]
[x+1,y],加入
f
r
o
m
[
i
]
∈
from[i]\in
from[i]∈ 这个区间,那么就将区间右端点与当前的数取
m
a
x
max
max。
我们考虑分块,记
f
[
i
]
[
b
l
]
f[i][bl]
f[i][bl] 表示询问为
(
i
,
R
[
b
l
]
)
(i,R[bl])
(i,R[bl]) 的答案,然后考虑如何预处理它。记
t
o
[
i
]
[
b
l
]
to[i][bl]
to[i][bl] 表示以
i
i
i 为左端点的线段最远的右端点,首先
f
[
i
]
[
b
l
]
=
g
[
i
]
[
b
l
]
f[i][bl]=g[i][bl]
f[i][bl]=g[i][bl]。从大到小枚举
i
i
i 然后用
j
∈
[
i
+
1
,
R
[
b
l
]
]
j\in[i+1,R[bl]]
j∈[i+1,R[bl]] 的
j
j
j 更新
f
[
i
]
[
b
l
]
f[i][bl]
f[i][bl]。如果
k
1
<
k
2
k_1<k_2
k1<k2 且
f
[
k
1
]
[
b
l
]
<
f
[
k
2
]
[
b
l
]
f[k_1][bl]<f[k_2][bl]
f[k1][bl]<f[k2][bl] 那么
k
1
k_1
k1 就没用了,所以用单调栈维护用来更新
f
[
i
]
[
b
l
]
f[i][bl]
f[i][bl] 的
k
k
k,碰到上面的情况就弹掉,并用最后一个弹掉的
k
k
k 的
f
[
k
]
[
b
l
]
f[k][bl]
f[k][bl] 更新
f
[
i
]
[
b
l
]
f[i][bl]
f[i][bl]。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<map>
#include<queue>
using namespace std;
const int N=1e5+5;
const int S=325;
const int s=317;
int n,m,q,l,r,top;
int bel[N],L[N],R[N],from[N],to[N][S],sta[N],f[N][S];
inline int read()
{
int s=0,t=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
return s*t;
}
inline int bfquery(int L,int R,int l,int r)
{
for(int i=l;i<=r;++i)
if(from[i]&&from[i]>=L&&from[i]<=R) R=max(R,i);
return R;
}
inline int query(int l,int r)
{
if(bel[l]==bel[r]) return bfquery(l,l,l+1,r);
else
{
int bl=bel[r]-1;
int pos=max(l,f[l][bl]);
return bfquery(l,pos,R[bl]+1,r);
}
}
int main()
{
n=read();
m=read();
for(int i=1;i<=n;++i)
{
bel[i]=(i-1)/s+1;
if(bel[i]!=bel[i-1]) L[bel[i]]=i;
R[bel[i]]=i;
}
while(m--)
{
l=read();
r=read();
to[l][bel[r]]=max(to[l][bel[r]],r);
from[r]=l;
}
for(int i=1;i<=n;++i)
for(int bl=1;bl<=bel[n];++bl)
to[i][bl]=max(to[i][bl],to[i][bl-1]);
for(int bl=1;bl<=bel[n];++bl)
{
sta[top=0]=0;
for(int i=n;i;--i)
{
f[i][bl]=to[i][bl];
while(top&&sta[top]<=to[i][bl])
{
f[i][bl]=max(f[i][bl],f[sta[top]][bl]);
--top;
}
sta[++top]=i;
}
}
q=read();
while(q--)
{
l=read();
r=read();
printf("%d\n",query(l,r));
}
return 0;
}
桥梁
题目
因为动态修改很烦所以对于操作分块。在每个块中,