CF466E
这个人只会做这种水题了。。。
Solution
直接做显然不太好做,考虑把询问离线下来在静态森林中查询。
对于操作 1,直接连边就可以了。
对于操作 2,容易发现能看到这个文件的一定是一条从祖先到子节点的一条链,记录这个文件被看到的链顶和链底即可。
对于操作 3,只需要知道
利用这条链是祖先向下的性质,
判断是否在子树中直接欧拉序就好了。
#include <bits/stdc++.h>
#define rep(i, j, k) for(int i = (j); i <= (k); i ++)
#define per(i, j, k) for(int i = (j); i >= (k); i --)
#define all(x) x.begin(), x.end()
#define sz(x) (int)x.size()
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
const int N = 1e5 + 5, INF = 0x3f3f3f3f;
const LL mod = 1e9 + 7;
int n, m, idx;
vector<int> e[N];
int st[N], ed[N];
int fa[N];
int L[N], R[N], tim;
vector<array<int, 3>> event;
int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void dfs(int u) {
L[u] = ++ tim;
for(auto v : e[u]) dfs(v);
R[u] = tim;
}
bool ins(int u, int v) { // v 是否在 u子树里
return L[u] <= L[v] && L[v] <= R[u];
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
cin >> n >> m;
rep(i, 1, n) fa[i] = i;
while(m --) {
int op, u, v;
cin >> op >> u;
if(op == 1) {
cin >> v;
e[v].push_back(u);
fa[u] = find(v);
}
else if(op == 2) {
st[++ idx] = find(u);
ed[idx] = u;
}
else {
cin >> v;
event.push_back({st[v], ed[v], u});
}
}
rep(i, 1, n) if(find(i) == i) dfs(i);
for(auto evt : event) {
if(ins(evt[0], evt[2]) && ins(evt[2], evt[1])) cout << "YES\n";
else cout << "NO\n";
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现