首页 > 代码库 > Acdream 1424 Diversion 树链剖分+线段树
Acdream 1424 Diversion 树链剖分+线段树
题意:
给定n个城市,和一些道路,道路有两种,一种是石头路,还有一种是乡村路,石头路形成了一棵树,即两两城市都可达,乡村路的加入使所有的石头路都处于一个或多个环中,即任意石头路被破坏后,城市间依然可以通过乡村路连通,现在敌国可以破坏一条石头路和一条乡村路,问,有多少种破坏方案,可以使破坏后,至少有一对城市不能互相到达。
题解:
仔细想想可以发现,石头路形成了一棵树,当这棵树上某一段道路被乡村路只覆盖一次时,那么破坏掉这条乡村路,这段路上的所有石头路破坏任意一条都能满足条件,所以只需要先把石头路形成的树剖分成链,然后用线段树来依次将乡村路往上覆盖,最后只需统计被覆盖次数为1的道路即为答案
代码:
#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 树链剖分+线段树
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。