题目链接:https://codeforces.com/contest/1851/problem/G
大致题意:
给出n个点m条边的无向图,每个点有点权h【i】。从点 i 到 点 j会消耗 h【j】 - h【i】 的能量,如果小于0,那么就是恢复对应绝对值的能量。
进行q次询问,每次询问包含起点s,终点t,能量e,能量在移动过程 中不能小于0,问是否能从s到t;
解题思路:
转化问题(结合律,然后抵消中间项),相当于不经过h【s】 + e的点,s和e是否连通;
然后无向图连通问题可以用并查集来维护;
考虑离线做法,我们对能量进行排序(从小到大);
然后依次建边合并,查询即可;
时间复杂度:O(nlogn);
代码:
#include<bits/stdc++.h> const int N = 2e5 + 5; int p[N], h[N]; int FIND(int x) { return p[x] = (x == p[x] ? x : FIND(p[x])); } struct I { int u, v, h, op, id; }; bool my_cmp(I a, I b) { if (a.h != b.h)return a.h < b.h; if (a.op != b.op)return a.op < b.op; return a.id < b.id; } signed main() { std::ios::sync_with_stdio(false); std::cin.tie(0); std::cout.tie(0); int T; std::cin >> T; while (T--) { int n, m; std::cin >> n >> m; for (int i = 1; i <= n; ++i)std::cin >> h[i], p[i] = i; std::vector<I> U; for (int i = 1; i <= m; ++i) { int a, b; std::cin >> a >> b; U.push_back({a, b, std::max(h[a], h[b]), 0, N + i}); } int q; std::cin >> q; for (int i = 1; i <= q; ++i) { int a, b, x; std::cin >> a >> b >> x; U.push_back({a, b, h[a] + x, 1, i}); } std::sort(U.begin(), U.end(), my_cmp); /*for (int i = 0; i < U.size(); ++i) std::cout << U[i].u << " " << U[i].v << " " << U[i].h << " " << U[i].op << " " << U[i].id << "\n";*/ std::vector<int> ans(q + 1, 0); for (int i = 0; i < U.size(); ++i) { if (U[i].op)ans[U[i].id] = (FIND(U[i].u) == FIND(U[i].v)); else p[FIND(U[i].u)] = FIND(U[i].v); } for (int i = 1; i <= q; ++i)std::cout << (ans[i] ? "YES\n" : "NO\n"); std::cout << "\n"; } return 0; }
不是很难的图论+数据结构的题目,但是码量还是有点大的:)
标签:std,Mountains,return,Vlad,int,888,cin,FIND,op From: https://www.cnblogs.com/ACMER-XiCen/p/17660109.html