【题解】「JOISC 2017 Day 3」幽深府邸

dfs + dp 好题

本题考察了对记忆化搜索的应用。

首先不难发现,以位置 i i i 作为起点可以扩展出区间 [ L , R ] [L,R] [L,R] ,且满足 L ≤ i ≤ R L\leq i\leq R LiR

那么我们的任务就是对于每一个 i i i ,找到它的极大区间。

假设当前扩展到了 [ L , R ] [L,R] [L,R] ,考虑 L − 1 L-1 L1 R + 1 R+1 R+1 能否扩展得到,相当于对 i i i L − 1 L-1 L1 连一条边,然后对 L − 1 L-1 L1 进行子问题求解,更新 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"); } } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530334.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(28)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示