[BZOJ5279][Usaco2018 Open]Disruption
Description
Farmer John自豪于他所经营的交通发达的的农场。这个农场是由N块牧场(2≤N≤50,000)组成的,N?1条双向道
路将它们连接起来,每一条道路的都为一单位长度。Farmer John注意到,从任何一块牧场到另一块牧场,都能通
过一组合适的道路到达。尽管FJ的农场现在是连通的,他担心如果有一条道路被阻断会发生什么,因为这事实上会
将他的农场分为两个不相交的牧场集合,奶牛们只能够在每一个集合内移动但不能在集合间移动。于是FJ又建造了
M条额外的双向道路(1≤M≤50,000),每一条的长度都是一个至多为10^9的正整数。奶牛们仍然可以使用原有的
道路进行移动,除非其中的某些被阻断了。如果某条原有的道路被阻断了,农场就会被分为两块不相交的区域,那
么FJ就会从他的额外修建的道路中选择一条能够重建这两块区域的连通性的,取代原来那条,从而奶牛们又可以从
任何一块牧场去往另一块牧场。对于农场上每一条原有的道路,帮助FJ选出最短的替代用的道路。
Input
输入的第一行包含N和M。接下来的N-1行,每行用整数p和q描述了一条原有的道路
其中p≠q是这条道路连接的两块牧场(在1…N范围内)。
剩下的M行,每行用三个整数p、q和r描述了一条额外的道路,其中r是这条道路的长度。
任何两块牧场之间至多只有一条道路。
Output
对原有的N-1条道路的每一条,按照它们在输入中出现的顺序
输出如果这条道路被阻断的话,能够重新连接农场的最短的替代用道路的长度。
如果不存在合适的替代用的道路,输出-1。
Sample Input
6 3
1 2
1 3
4 1
4 5
6 5
2 3 7
3 6 8
6 4 5
1 2
1 3
4 1
4 5
6 5
2 3 7
3 6 8
6 4 5
Sample Output
7
7
8
5
5
7
8
5
5
这题显然的树剖吧..应该很好看出来。
我们发现一条边$(x,y)$可以解决$x$到$y$之间的边,意思就是在点$x$到点$y$之间的边断掉,都可以用这条非树边连回去。
于是把非树边按权值从大到小排序,然后每次用线段树把$x$到$y$区间中的树边的答案修改掉,
按权值从大到小保证小的边权可以覆盖大的边权。
要注意的是,我们把边权寄托到了它下面的点的点权上,我们在修改的时候如果$x$和$y$在同一条链上的时候(假设$dep[x]<dep[y]$),只能修改$x$的儿子节点到$y$之间的边。
然后这水题就做完了,毕竟我就写了不到20分钟?
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <vector> #include <map> using namespace std; #define reg register inline int read() { int res = 0;char ch=getchar();bool fu=0; while(!isdigit(ch))fu|=(ch=='-'),ch=getchar(); while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar(); return fu?-res:res; } #define N 50005 int n, m; struct edge { int nxt, to, from, id; }ed[N<<1]; int head[N], cnt; inline void add(int x, int y, int id) { ed[++cnt] = (edge){head[x], y, x, id}; head[x] = cnt; } struct date { int x, y, val; inline bool operator < (const date &a) const { return val > a.val; } }da[N]; int ans[N]; int Fa[N], top[N], id[N], rnk[N], dep[N], siz[N], son[N], tot; void dfs1(int x, int fa) { Fa[x] = fa, dep[x] = dep[fa] + 1, siz[x] = 1; for (reg int i = head[x] ; i ; i = ed[i].nxt) { int to = ed[i].to; if (to == fa) continue; dfs1(to, x); siz[x] += siz[to]; if (siz[to] > siz[son[x]]) son[x] = to; } } void dfs2(int x, int tep) { id[x] = ++tot, rnk[tot] = x; top[x] = tep; if (son[x]) dfs2(son[x], tep); for (reg int i = head[x] ; i ; i = ed[i].nxt) { int to = ed[i].to; if (to == Fa[x] or to == son[x]) continue; dfs2(to, to); } } int tr[N << 2], lzy[N << 2]; #define ls o << 1 #define rs o << 1 | 1 inline void pushup(int o) { tr[o] = tr[ls] + tr[rs]; } inline void spread(int o, int l, int r) { if (!lzy[o]) return; lzy[ls] = lzy[rs] = lzy[o]; int mid = (l + r) >> 1; tr[ls] = lzy[o] * (mid - l + 1); tr[rs] = lzy[o] * (r - mid); lzy[o] = 0; } void change(int l, int r, int o, int ql, int qr, int c) { if (l >= ql and r <= qr) { tr[o] = (r - l + 1) * c; lzy[o] = c; return ; } spread(o, l, r); int mid = (l + r) >> 1; if (ql <= mid) change(l, mid, ls, ql, qr, c); if (qr > mid) change(mid + 1, r, rs, ql, qr, c); pushup(o); } void changes(int x, int y, int c) { while(top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) swap(x, y); change(1, n, 1, id[top[x]], id[x], c); x = Fa[top[x]]; } if (id[x] > id[y]) swap(x, y); change(1, n, 1, id[x] + 1, id[y], c); } int query(int l, int r, int o, int p) { // printf("%d %d %d\n", l, r, tr[o]); if (l == r) return tr[o]; spread(o, l, r); int mid = (l + r) >> 1; if (p <= mid) return query(l, mid, ls, p); else return query(mid + 1, r, rs, p); } int main() { n = read(), m = read(); for (reg int i = 1 ; i < n ; i ++) { int x = read(), y = read(); add(x, y, i), add(y, x, i); } for (reg int i = 1 ; i <= m ; i ++) da[i] = (date){read(), read(), read()}; sort(da + 1, da + 1 + m); dfs1(1, 0); dfs2(1, 1); // for (int i=1;i<=n;i++) printf("siz[%d]=%d\n", i, siz[i]); for (reg int i = 1 ; i <= m ; i ++) changes(da[i].x, da[i].y, da[i].val); for (reg int i = 1 ; i <= cnt ; i += 2) { int x = ed[i].from, y = ed[i].to; if (dep[x] < dep[y]) swap(x, y); ans[ed[i].id] = query(1, n, 1, id[x]); // printf("%d\n",x); } for (reg int i = 1 ; i < n ; i ++) printf("%d\n", ans[i] > 0 ? ans[i] : -1); return 0; }