ABC295G
不难发现初始图
观察连边操作的限制:
- 保证在连这条边之前,存在一条由
到 的路径。
显然由于第二条限制,每次连边必然出环,也就必然出现强连通分量,强连通分量里任意两点可以相互到达,所以询问时就找强连通分量里编号最小的点。由于连的一定是返租边,所以用并查集维护强连通,合并时暴力往上跳即可。感性理解或者势能分析一下都能发现均摊复杂度(应该)是
代码:
#include<bits/stdc++.h>
#define endl '\n'
#define rep(i, s, e) for(int i = s, i##E = e; i <= i##E; ++i)
#define per(i, s, e) for(int i = s, i##E = e; i >= i##E; --i)
#define F first
#define S second
//#define int ll
#define gmin(x, y) ((x > y) && (x = y))
#define gmax(x, y) ((x < y) && (x = y))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double f128;
typedef pair<int, int> pii;
constexpr int N = 2e5 + 5;
int n, q, pa[N], fa[N];
int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
vector<int> to[N];
signed main() {
#ifdef ONLINE_JUDGE
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
#endif
cin >> n;
rep(i, 1, n - 1) {
int x; cin >> x;
pa[i + 1] = x;
to[x].push_back(i + 1);
}
iota(fa + 1, fa + n + 1, 1);
cin >> q;
while(q--) {
int op; cin >> op;
if(op == 1) {
int x, y; cin >> x >> y;
y = find(y);
for(int i = x; i != y; i = pa[i]) {
i = find(i);
if(i == y) break;
fa[i] = y;
}
}
else {
int x; cin >> x;
cout << find(x) << endl;
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构