zoukankan      html  css  js  c++  java
  • 树链剖分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
    ", query(l, r));
        }
    }
    
    int main() {
        //freopen("test.in", "r", stdin);
        read();
        sov();
        return 0;
    }
    
  • 相关阅读:
    jQuery学习教程(一):入门
    jQuery学习教程(八):事件
    jQuery学习教程(五):选择器综合实例
    jQuery学习教程(六):属性操作与CSS操作
    jQuery学习教程(四):使用jQuery操作DOM
    jQuery学习教程(七):val()与节点操作
    jQuery学习教程(二):选择器1
    const的使用
    ASP.NET 页面间传值的方法
    .net中接口与基类
  • 原文地址:https://www.cnblogs.com/ianaesthetic/p/3873053.html
Copyright © 2011-2022 走看看