zoukankan      html  css  js  c++  java
  • HDU-6547 Tree (树链剖分,线段树区间开根号)

    题目链接:HDU-6547 Tree

    题意

    wls 有三棵树,树上每个节点都有一个值 $a_i$,现在有 2 种操作: 
    1. 将一条链上的所有节点的值开根号向下取整; 
    2. 求一条链上值的和; 
    链的定义是两点之间的最短路。


    思路

    树链剖分裸题,区间开根号可用线段树做,利用 $10^9$ 范围内的数经过少数几次开根号之后就会达到 1,标记线段树区间最大值,若为 1 则无需再往下更新。

    树链剖分传送门:https://www.cnblogs.com/kangkang-/p/8486150.html


    代码实现

    #include <stdio.h>
    #include <iostream>
    #include <cmath>
    #define REP(i, a, b) for (int i = a; i <= b; i++)
    using namespace std;
    typedef long long LL;
    const double esp = 1e-8;
    const int MAXN = 110000;
    struct Node {
        int to, next;
    } edg[MAXN<<1];
    struct segmentTree {
        int left, right;
        LL sum, maxx;
    } tree[MAXN<<2];
    int head[MAXN], siz[MAXN], top[MAXN], hson[MAXN], dep[MAXN], fa[MAXN], id[MAXN], rnk[MAXN];
    int N, M, R, A[MAXN], idx = 0, dfs_cnt = 0;
    inline int read() {
        int x = 0, f = 1; char ch = getchar();
        while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
        while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
        return x * f;
    }
    inline void adde(int u, int v) {
        edg[++idx].to = v; edg[idx].next = head[u]; head[u] = idx;
    }
    void dfs1(int u, int father, int depth) {
        dep[u] = depth;
        fa[u] = father;
        siz[u] = 1;
        for (int i = head[u]; i; i = edg[i].next) {
            int v = edg[i].to;
            if (v != fa[u]) {
                dfs1(v, u, depth + 1);
                siz[u] += siz[v];
                if (hson[u] == -1 || siz[v] > siz[hson[u]]) hson[u] = v;
            }
        }
    }
    void dfs2(int u, int t) {
        id[u] = ++dfs_cnt; rnk[dfs_cnt] = u; top[u] = t;
        if (!hson[u]) return ;
        dfs2(hson[u], t);
        for (int i = head[u]; i; i = edg[i].next) {
            int v = edg[i].to;
            if (v != hson[u] && v != fa[u]) dfs2(v, v);
        }
    }
    void buildtree(int i, int l, int r) {
        tree[i].left = l; tree[i].right = r;
        if (l == r) tree[i].sum = tree[i].maxx = A[rnk[l]];
        else {
            int mid = (l + r) >> 1;
            buildtree(i << 1, l , mid);
            buildtree(i << 1 | 1, mid + 1, r);
            tree[i].sum = tree[i<<1].sum + tree[i<<1|1].sum;
            tree[i].maxx = max(tree[i<<1].maxx, tree[i<<1|1].maxx);
        }
    }
    void update(int i, int x, int y) {
        if (tree[i].left > y || tree[i].right < x) return ;
        if (tree[i].left == tree[i].right) {
            tree[i].maxx = sqrt(tree[i].maxx) + esp;
            tree[i].sum = sqrt(tree[i].sum) + esp;
            return ;
        }
        if (tree[i].maxx == 1) return ;
        int l = i << 1, r = i << 1 | 1;
        update(l, x, y);
        update(r, x, y);
        tree[i].sum = tree[l].sum + tree[r].sum;
    }
    LL query(int i, int x, int y) {
        int l = i << 1, r = i << 1 | 1;
        if (x <= tree[i].left && tree[i].right <= y) return tree[i].sum;
        if (tree[i].left > y || tree[i].right < x) return 0;
        return query(l, x, y) + query(r, x, y);
    }
    void update_path(int u, int v) {
        int tu = top[u], tv = top[v];
        while (tu != tv) {
            if (dep[tu] < dep[tv]) swap(u, v), swap(tu, tv);
            update(1, id[tu], id[u]);
            u = fa[tu], tu = top[u];
        }
        if (dep[u] < dep[v]) swap(u, v);
        update(1, id[v], id[u]);
    }
    LL query_path(int u, int v) {
        LL res = 0;
        int tu = top[u], tv = top[v];
        while (tu != tv) {
            if (dep[tu] < dep[tv]) swap(u, v), swap(tu, tv);
            res += query(1, id[tu], id[u]);
            u = fa[tu], tu = top[u];
        }
        if (dep[u] < dep[v]) swap(u, v);
        return res + query(1, id[v], id[u]);
    }
    
    int main() {
        N = read(), M = read(), R = 1;
        REP(i, 1, N) A[i] = read();
        REP(i, 2, N) {
            int u = read(), v = read();
            adde(u, v); adde(v, u);
        }
        dfs1(R, 0, 1);
        dfs2(R, R);
        buildtree(1, 1, N);
        while (M--) {
            int opt = read();
            switch (opt) {
                case 0: {
                    int x = read(), y = read();
                    LL z;
                    update_path(x, y);
                    break;
                }
                case 1: {
                    int x = read(), y = read();
                    printf("%lld
    ", query_path(x, y));
                    break;
                }
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    智能移动机器人背后蕴含的技术——激光雷达
    Kalman Filters
    Fiddler抓HttpClient的包
    VSCode开发WebApi EFCore的坑
    WPF之小米Logo超圆角的实现
    windows react打包发布
    jenkins in docker踩坑汇总
    Using ML.NET in Jupyter notebooks 在jupyter notebook中使用ML.NET ——No design time or full build available
    【Linux知识点】CentOS7 更换阿里云源
    【Golang 报错】exec gcc executable file not found in %PATH%
  • 原文地址:https://www.cnblogs.com/kangkang-/p/11648873.html
Copyright © 2011-2022 走看看