首页 > 其他 > 详细

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

时间:2014-07-28 19:14:54      阅读:428      评论:0      收藏:0      [点我收藏+]

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

 

树链剖分2——边权改点权,布布扣,bubuko.com

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

原文:http://www.cnblogs.com/ianaesthetic/p/3873053.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!