实验对象——2013 noip day1 T3
本来可以直接用倍增lca解决。。但是我比较的扯淡。。所以用树链剖分来搞
和普通点权不同的是,对于一颗树来说,每一个点的点权被定义为他的父亲到他的边权,所以与一般的树链剖分相比,最后统一到一条链上时,线段树维护的一边端点要加1。。其他的就没了。然后注意往上跳的时候的比较时dep[un[a]] 和 dep[un[b]] 不是dep[a] dep[b];
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxe = 100001; const int maxn = 100010; const int inf = 0x3f3f3f3f; struct line { int l, r, d; }s[maxe]; struct edge { int t, d; edge* next; }e[maxn * 2], *head[maxn]; int ne = 0; void addedge(int f, int t, int d) { e[ne].t = t, e[ne].d = d, e[ne].next = head[f], head[f] = e + ne ++; } int int_get() { char c; int x = 0; c = (char)getchar(); while(!isdigit(c)) c = (char)getchar(); while(isdigit(c)) { x = x * 10 + (int)(c - '0'); c = (char)getchar(); } return x; } int n, m; int father[maxn]; int find(int x) { return x == father[x] ? x : find(father[x]); } bool cmp(line a, line b) { return a.d > b.d; } int h[maxn], fa[maxn], un[maxn], map[maxn]; int w[maxn]; int size[maxn]; struct node { int key; node* l, *r; }se[maxn * 3], *root; int ns = 0; node* build(int l, int r) { node* now = se + ns ++; if(l ^ r) { int mid = (l + r) >> 1; now-> l = build(l, mid); now-> r = build(mid + 1, r); } return now; } void update(node* x) { if(x-> l) x-> key = min(x-> l-> key, x-> r-> key); } void insert(node* now, int l, int r, int pos, int v) { if(l == r) now-> key = v; else { int mid = (l + r) >> 1; if(pos <= mid) insert(now-> l, l, mid, pos, v); else insert(now-> r, mid + 1, r, pos, v); update(now); } } int _query(node* now, int l, int r, int ls, int rs) { if(l == ls && r == rs) return now-> key; else { int mid = (l + r) >> 1; if(rs <= mid) return _query(now-> l, l, mid, ls, rs); else if(ls >= mid + 1) return _query(now-> r, mid + 1, r, ls, rs); else return min(_query(now-> l, l, mid, ls, mid), _query(now-> r, mid + 1, r, mid + 1, rs)); } } void dfs(int x, int pre) { if(pre == -1) { h[x] = 1, fa[x] = x; w[x] = inf; } else h[x] = h[pre] + 1, fa[x] = pre; size[x] = 1; for(edge* p = head[x]; p; p = p-> next) { if(!h[p-> t]) { dfs(p-> t, x); w[p-> t] = p-> d; size[x] += size[p-> t]; } } } int tot = 0; void _union(int x, int pre) { if(pre == -1) un[x] = x; else un[x] = pre; map[x] = ++ tot; insert(root, 1, n, map[x], w[x]); int smax = 0; int pos = 0; for(edge* p = head[x]; p; p = p-> next) { if(h[p-> t] > h[x]) { if(size[p-> t] > smax) smax = size[p-> t], pos = p-> t; } } if(!smax) return; else { _union(pos, un[x]); for(edge* p = head[x]; p; p = p-> next) { if(h[p-> t] > h[x] && p-> t != pos) { _union(p-> t, -1); } } } } void pre() { for(int i = 1; i <= n; ++ i) father[i] = i; sort(s + 1, s + 1 + m, cmp); int cnt = 0; for(int i = 1; i <= m && cnt <= n; ++ i) { int fx = find(s[i].l); int fy = find(s[i].r); if(fx != fy) { father[fy] = fx; ++ cnt; addedge(s[i].l, s[i].r, s[i].d); addedge(s[i].r, s[i].l, s[i].d); } } } void read() { n = int_get(), m = int_get(); for(int i = 1; i <= m; ++ i) { s[i].l = int_get(); s[i].r = int_get(); s[i].d = int_get(); } root = build(1, n); } int Q = 0; int query(int a, int b) { if(find(a) != find(b)) return -1; int ret = inf; while(un[a] != un[b]) { if(h[un[a]] > h[un[b]]) { int rs= map[a], ls = map[un[a]]; if(ls > rs) {a = fa[un[a]]; continue;} ret = min(ret, _query(root, 1, n, ls, rs)); a = fa[un[a]]; } else { int rs = map[b], ls = map[un[b]]; if(ls > rs) {b = fa[un[b]]; continue;} ret = min(ret, _query(root, 1, n, ls, rs)); b = fa[un[b]]; } } if(a != b) { if(h[a] < h[b]) swap(a, b); int rs = map[a], ls = map[b] + 1; if(ls <= rs) { ret = min(ret, _query(root, 1, n, ls, rs)); } } return ret; } void sov() { pre(); for(int i = 1; i <= n; ++ i) { if(!h[i]) { dfs(i, -1); _union(i, -1); } } Q = int_get(); while(Q --) { int l, r; scanf("%d%d", &l, &r); printf("%d\n", query(l, r)); } } int main() { //freopen("test.in", "r", stdin); read(); sov(); return 0; }