dfs + dp 好题
本题考察了对记忆化搜索的应用。
首先不难发现,以位置 i i i 作为起点可以扩展出区间 [ L , R ] [L,R] [L,R] ,且满足 L ≤ i ≤ R L\leq i\leq R L≤i≤R 。
那么我们的任务就是对于每一个 i i i ,找到它的极大区间。
假设当前扩展到了 [ L , R ] [L,R] [L,R] ,考虑 L − 1 L-1 L−1 和 R + 1 R+1 R+1 能否扩展得到,相当于对 i i i 到 L − 1 L-1 L−1 连一条边,然后对 L − 1 L-1 L−1 进行子问题求解,更新 L = m i n ( L , L x ) L=min(L,L_x) L=min(L,Lx) , R = m a x ( R , R x ) R=max(R,R_x) R=max(R,Rx) 。注意将正在遍历的点设为 1 1 1 ,如果 v i s [ x ] = 1 vis[x]=1 vis[x]=1 则跳出。
那么就有一个很优美的性质,对于每一个点 i i i ,我们只进行一次扩展,而且会得到极大区间,同时我们借助了已经跑出的 d p dp dp 值,加快了这一过程。
时间复杂度最坏 O ( n 2 ) O(n^2) O(n2) ,但是如果均摊的话,大概是 O ( n l o g n ) O(nlogn) O(nlogn) 的级别。
#include <bits/stdc++.h>
using namespace std;
const int mx = 5e5 + 5;
inline int read() {
int X = 0;
bool flag = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
flag = 0;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
X = (X << 1) + (X << 3) + ch - '0';
ch = getchar();
}
if (flag)
return X;
return ~(X - 1);
}
int n, q, l[mx], r[mx], id[mx], ky[mx], L[mx], R[mx], ps[mx], c[mx], ins[mx];
void dfs(int x) {
if (ins[x])
return;
ins[x] = 1;
L[x] = R[x] = x;
int ok = 1;
while (ok) {
ok = 0;
int tl = L[x] - 1, tr = R[x] + 1;
if (r[tl] && r[tl] < tr) {
dfs(tl);
if (L[tl] < L[x])
L[x] = L[tl], ok = 1;
if (R[tl] > R[x])
R[x] = R[tl], ok = 1;
}
if (l[tr] && l[tr] > tl) {
dfs(tr);
if (L[tr] < L[x])
L[x] = L[tr], ok = 1;
if (R[tr] > R[x])
R[x] = R[tr], ok = 1;
}
}
}
int main() {
// freopen("data.in","r",stdin);
n = read();
for (int i = 1; i < n; i++)
c[i] = read();
for (int i = 1; i <= n; i++) {
id[i] = id[i - 1] + read();
for (int j = id[i - 1] + 1; j <= id[i]; j++) {
ky[j] = read();
}
}
for (int i = n; i > 1; i--) {
for (int j = id[i - 1] + 1; j <= id[i]; j++) {
ps[ky[j]] = i;
}
r[i - 1] = ps[c[i - 1]];
}
for (int i = 1; i <= n; i++)
ps[i] = 0;
for (int i = 1; i < n; i++) {
for (int j = id[i - 1] + 1; j <= id[i]; j++) {
ps[ky[j]] = i;
}
l[i + 1] = ps[c[i]];
}
for (int i = 1; i <= n; i++)
dfs(i);
q = read();
for (int i = 1; i <= q; i++) {
int x = read(), y = read();
if (L[x] <= y && y <= R[x]) {
printf("YES\n");
} else {
printf("NO\n");
}
}
}