题解:CF1814F Communication Towers
巨佬们怎么都打的线段树分治?!
一种很清奇的思路:树状 DP
(虽然这是个图,但感觉叫它树状也没啥问题)
或者说这个算法是 DFS。
我们先看一下下面这个样例:
每个圆圈里的数字代表编号,下面的中括号代表工作频率。
重审题意,要求只要在某一频率下一个点能和
那么我们就可以从点
比如说,我们来到了
那么我们取点
再从点
再从点
大体思路是这样,但我们需要考虑出口和剪枝。
比如我们从点
但我们如果以
到这里思路就已经结束了,理论可行,上代码:
Code
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 2e5 + 5, M = N << 1;
int n, m;
bool ans[N];
vector <int> road[N];
vector <pair <int, int>> once[N];
inline pair <int, int> get (int p, pair <int, int> x) {
x.first = max(x.first, once[p][0].first),
x.second = min(x.second, once[p][0].second);
for (int i = 1; i < once[p].size(); i ++) {
pair <int, int> th = once[p][i];
if (th.first <= x.first and th.second >= x.second) return {-1, 0};
else if (th.first > x.second or th.second < x.first) continue;
else if (x.first < th.first and x.second <= th.second) {
x.second = th.first - 1;
}
else if (th.first <= x.first and th.second < x.second) {
x.first = th.second + 1;
}
}
return x;
}
void dfs (int p, int Jn, pair <int, int> now) {
pair <int, int> g = get(p, now);
if (g.first == -1) return;
if (g.first > g.second) return;
once[p].push_back(g);
ans[p] = 1;
for (int i = 0; i < road[p].size(); i ++) {
if (road[p][i] != Jn) dfs(road[p][i], p, g);
}
}
int main () {
cin >> n >> m;
int u, v;
for (int i = 1; i <= n; i ++) {
cin >> u >> v;
once[i].push_back({u, v});
}
for (int i = 1; i <= m; i ++) {
cin >> u >> v;
road[u].push_back(v);
road[v].push_back(u);
}
dfs(1, 0, once[1][0]);
for (int i = 1; i <= n; i ++) {
if (ans[i]) cout << i << ' ';
}
return 0;
}