首页 > 代码库 > 树链剖分2——边权改点权

树链剖分2——边权改点权

实验对象——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;}