Question:
Given n cities and some roads, there are two types of roads, one is stone road and the other is country road. The stone road forms a tree, that is, the two cities are reachable, the addition of country roads puts all stone roads in one or more rings. That is to say, after any stone road is damaged, it can still be connected between cities through country roads, now, the enemy can destroy one stone road and one rural road and ask how many types of damage solutions can prevent at least one city from reaching each other after the damage.
Question:
Think about it and you can find that the rock road forms a tree. When a certain section of the tree is covered only once by the Village Road, it will destroy the village road, all stone roads on this road can meet any condition, so you only need to first split the tree formed by the stone road into a chain, and then use the line segment tree to cover the Village Road in sequence, finally, you only need to count the road where the number of times covered is 1 as the answer.
Code:
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxn = 2e4 + 10;const int maxe = 1e5 + 10;int fir[maxn], nxt[maxe<<1], edge[maxe<<1], cnt_edge;void add_edge(int u, int v){ edge[cnt_edge] = v; nxt[cnt_edge] = fir[u]; fir[u] = cnt_edge++; edge[cnt_edge] = u; nxt[cnt_edge] = fir[v]; fir[v] = cnt_edge++;}int fa[maxn], son[maxn], sz[maxn], dep[maxn];int id[maxn], top[maxn], num, root;struct{ void init() { root = 1; fa[root] = num = dep[root] = 0; } void dfs(int u) { sz[u] = 1; son[u] = 0; for (int i = fir[u]; i != -1; i = nxt[i]) { int v = edge[i]; if (v == fa[u]) continue; fa[v] = u; dep[v] = dep[u] + 1; dfs(v); sz[u] += sz[v]; if (sz[son[u]] < sz[v]) son[u] = v; } } void build_tree(int u, int tp) { id[u] = num++; top[u] = tp; if (son[u]) build_tree(son[u], top[u]); for (int i = fir[u]; i != -1; i = nxt[i]) { int v = edge[i]; if (son[u] == v || v == fa[u]) continue; build_tree(v, v); } } void run() { init(); dfs(root); build_tree(root, root); num--; }}div_chain;int n, m;struct Road{ int u, v; Road(int u = 0, int v = 0) : u(u), v(v) {}}road[maxe];int road_cnt;struct segment{#define lson o<<1, L, M#define rson o<<1|1, M+1, R int col[maxe<<2]; void build(int o, int L, int R) { col[o] = 0; if (L <= R) return ; int M = (L + R) >> 1; build(lson); build(rson); } void PushDown(int o) { if (col[o]) { col[o<<1] += col[o]; col[o<<1|1] += col[o]; col[o] = 0; } } void update(int p1, int p2, int v, int o, int L, int R) { if (p1 <= L && p2 >= R) { col[o] += v; return ; } PushDown(o); int M = (L + R) >> 1; if (p1 <= M) update(p1, p2, v, lson); if (p2 > M) update(p1, p2, v, rson); } void Find(int a, int b) { int ta = top[a], tb = top[b]; while (ta != tb) { if (dep[ta] < dep[tb]) { swap(ta, tb); swap(a, b); } update(id[ta], id[a], 1, 1, 1, num); a = fa[ta]; ta = top[a]; } if (a == b) return; if (dep[a] < dep[b]) { swap(a, b); } update(id[son[b]], id[a], 1, 1, 1, num); } int query(int o, int L, int R) { if (L == R) { if (col[o] == 1) { return 1; } else return 0; } PushDown(o); int M = (L + R) >> 1; return query(lson) + query(rson); }}seg;int main(){ //freopen("/Users/apple/Desktop/in.txt", "r", stdin); while (scanf("%d%d", &n, &m) != EOF) { memset(fir, -1, sizeof(fir)); cnt_edge = 0, road_cnt = 0; for (int i = 0; i < m; i++) { int u, v, w; scanf("%d%d%d", &u, &v, &w); if (w == 1) add_edge(u, v); else road[road_cnt++] = Road(u, v); } div_chain.run(); seg.build(1, 1, num); for (int i = 0; i < road_cnt; i++) { seg.Find(road[i].u, road[i].v); } printf("%d\n", seg.query(1, 1, num)); } return 0;}
Acdream 1424 diversion tree segmentation + line segment tree