众所周知,一棵有 思路就是先将环去掉,对每一棵树做处理,最后再对环做处理。
P8943 Deception Point
这是一道基础的入门题。
我们发现,只要两个人能在到达环上之前不碰面(包括刚到达环上),那雷切尔就一定存活 ,否则就必死无疑,处理三角洲到达环上的距离与雷切尔到达环上的距离,再查看是否会在到达环上是碰面即可。
/*
The code was written by yifan, and yifan is neutral!!!
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 2e5 + 5;
int n, q, m;
int dep[N], top[N], fa[N], loop[N], dis[N];
bool ok[N];
vector<int> e[N];
void getloop(int u) {
dep[u] = dep[fa[u]] + 1;
for (int v : e[u]) {
if (v == fa[u]) continue ;
if (!dep[v]) {
fa[v] = u;
getloop(v);
}
else if (dep[v] < dep[u]) {
for (int i = u; ; i = fa[i]) {
ok[i] = 1;
loop[++ m] = i;
if (i == v) break;
}
}
}
}
void dfs(int u, int fat, int tp) {
top[u] = tp;
for (int v : e[u]) {
if (v == fat || ok[v]) continue ;
dep[v] = dep[u] + 1;
dfs(v, u, tp);
}
}
int main() {
n = read<int>(), q = read<int>();
for (int i = 1, x, y; i <= n; ++ i) {
x = read<int>(), y = read<int>();
e[x].emplace_back(y);
e[y].emplace_back(x);
}
getloop(1);
memset(dep, 0, sizeof dep);
for (int i = 1; i <= m; ++ i) {
dfs(loop[i], 0, i);
// cout << loop[i] << ' ';
}
while (q --) {
int x = read<int>(), y = read<int>();
int d1 = dep[x], t1 = top[x];
int d2 = dep[y], t2 = top[y];
if (d2 + min(abs(t1 - t2), m - abs(t1 - t2)) > d1) {
puts("Survive");
}
else {
puts("Deception");
}
}
return 0;
}
P8655 [蓝桥杯 2017 国 B] 发现环
简单的找环模板 = =||
/*
The code was written by yifan, and yifan is neutral!!!
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 1e5 + 5;
int n;
int dep[N], fa[N];
bool ok[N];
vector<int> e[N];
void getloop(int u) {
dep[u] = dep[fa[u]] + 1;
for (int v : e[u]) {
if (v == fa[u]) continue;
if (!dep[v]) {
fa[v] = u;
getloop(v);
}
else if (dep[v] < dep[u]) {
for (int i = u; ; i = fa[i]) {
ok[i] = 1;
if (i == v) break;
}
}
}
}
int main() {
n = read<int>();
for (int i = 1, x, y; i <= n; ++ i) {
x = read<int>(), y = read<int>();
e[x].emplace_back(y);
e[y].emplace_back(x);
}
getloop(1);
for (int i = 1; i <= n; ++ i) {
if (ok[i]) {
printf("%d ", i);
}
}
return 0;
}
P6037 Ryoku 的探索
朴素做法为 \(O_{n^2}\) 的。
但仔细观察,就会发现,最终答案一定是除去环上一条边,其他边的长度总和,删掉哪条边呢?根据美观度来判断。
/*
The code was written by yifan, and yifan is neutral!!!
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 1e6 + 5;
int n, m;
ll ans, sum;
int loop[N], top[N], fa[N], dep[N];
ll dis[N];
bool ok[N];
struct node {
int v;
ll w, p;
node(int a, ll b, ll c): v(a), w(b), p(c) {};
};
vector<node> e[N];
void getloop(int u) {
dep[u] = dep[fa[u]] + 1;
for (node it : e[u]) {
int v = it.v;
if (v == fa[u]) continue;
if (!dep[v]) {
fa[v] = u;
getloop(v);
}
else if (dep[v] < dep[u]) {
for (int i = u; ; i = fa[i]) {
ok[i] = 1;
loop[++ m] = i;
if (i == v) break;
}
}
}
}
void dfs(int u, int fat, int tp) {
top[u] = tp;
for (node it : e[u]) {
int v = it.v;
ll w = it.w;
if (v == fat || ok[v]) continue;
ans += w;
dfs(v, u, tp);
}
}
int main() {
n = read<int>();
for (int i = 1, x, y; i <= n; ++ i) {
x = read<int>(), y = read<int>();
ll w = read<ll>(), q = read<ll>();
e[x].emplace_back(y, w, q);
e[y].emplace_back(x, w, q);
}
getloop(1);
for (int i = 1; i <= m; ++ i) {
dfs(loop[i], 0, loop[i]);
}
loop[m + 1] = loop[1];
for (int i = 1; i <= m; ++ i) {
for (node it : e[loop[i]]) {
int v = it.v;
if (v == loop[i + 1]) {
dis[i] = it.w;
sum += it.w;
break;
}
}
}
for (int i = 1, u; i <= n; ++ i) {
u = top[i];
ll W = 0, P = 1e9;
for (node it : e[u]) {
int v = it.v;
ll w = it.w, p = it.p;
if (!ok[v]) continue;
if (p < P) {
W = w;
P = p;
}
}
printf("%lld\n", sum - W + ans);
}
return 0;
}