zoukankan      html  css  js  c++  java
  • [Vani有约会] 雨天的尾巴 /【模板】线段树合并

    题目链接

    Solution

    对每个节点维护一个权值线段树,线段树上就维护最大值以及最大值出现的节点。利用树上差分的思想,在 (x)(y) 位置 (+1),在 (LCA(x, y)) 位置 (-1)(fa_{LCA(x, y)}) 位置 (-1)

    更新完后不断把线段树向上合并。简单来说,当前线段树 = 该节点所有子树维护的线段树合并起来。

    注意!输出的时候一定要及时更新 ans,因为合并过程中可能会改变当前 ans。

    具体的线段树合并方式如下:

    int merge(int u, int v, int l, int r) //u 和 v 是要合并的两棵线段树(将 v 合并到 u 上)
    {
        if(!u) return v; //如果 u 不存在当前节点
        if(!v) return u; //如果 v 不存在当前节点
        if(l == r)
        {
            ; //你要维护的一些东西
            return u;
        }
        int mid = (l + r) >> 1;
        L[u] = merge(L[u], L[v], l, mid); //合并左子树
        R[u] = merge(R[u], R[v], mid + 1, r); //合并右子树
        push_up(u); return u;
    }
    

    Code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int N = 6000005, Z = 1e5 + 23;
    struct edge { int nxt, to; } e[N];
    int n, m, tot = 0, cnt = 0, last = 0;
    int head[N], dep[N], t[N], L[N], R[N], ans[N], maxx[N], f[N / 10][32], ANS[N];
    
    void add(int x, int y) { e[++tot] = (edge) { head[x], y }; head[x] = tot; }
    void dfs(int x, int Fa)
    {
        dep[x] = dep[Fa] + 1, f[x][0] = x, f[x][1] = Fa;
        for(int i = 2; i <= 30; i++) f[x][i] = f[f[x][i - 1]][i - 1];
        for(int i = head[x]; i; i = e[i].nxt) if(e[i].to != Fa) dfs(e[i].to, x);
    }
    int LCA(int a, int b)
    {
        if(dep[a] > dep[b]) swap(a, b);
        for(int i = 30; i >= 0; i--) if(dep[f[b][i]] >= dep[a]) b = f[b][i];
        if(a == b) return a;
        for(int i = 30; i >= 0; i--)
            if(f[b][i] != f[a][i]) b = f[b][i], a = f[a][i];
        return f[a][1];
    }
    
    void push_up(int x)
    {
        if(maxx[L[x]] >= maxx[R[x]]) maxx[x] = maxx[L[x]], ans[x] = ans[L[x]];
        else maxx[x] = maxx[R[x]], ans[x] = ans[R[x]];
    }
    int update(int pre, int l, int r, int x, int k)
    {
        if(!pre) pre = ++cnt;
        if(l == r)
        {
            ans[pre] = l;
            maxx[pre] += k;
            return pre;
        }
        int mid = (l + r) >> 1;
        if(x <= mid) L[pre] = update(L[pre], l, mid, x, k);
        else R[pre] = update(R[pre], mid + 1, r, x, k);
        push_up(pre);
        return pre;
    }
    int merge(int u, int v, int l, int r)
    {
        if(!u) return v;
        if(!v) return u;
        if(l == r)
        {
            maxx[u] = maxx[u] + maxx[v];
            ans[u] = l;
            return u;
        }
        int mid = (l + r) >> 1;
        L[u] = merge(L[u], L[v], l, mid);
        R[u] = merge(R[u], R[v], mid + 1, r);
        push_up(u); return u;
    }
    void solve(int x)
    {
        for(int i = head[x]; i; i = e[i].nxt)
        {
            int v = e[i].to;
            if(v != f[x][1]) solve(v), t[x] = merge(t[x], t[v], 1, Z);
        }
        if(maxx[t[x]]) ANS[x] = ans[t[x]];
    }
    
    int main()
    {
        scanf("%d%d", &n, &m);
        memset(f, 0, sizeof(f));
        memset(t, 0, sizeof(t));
        memset(head, 0, sizeof(head));
        memset(maxx, 0, sizeof(maxx));
        for(int x, y, i = 1; i < n; i++)
            scanf("%d%d", &x, &y), add(x, y), add(y, x);
        dep[0] = 0, dfs(1, 0);
        for(int x, y, z, i = 1; i <= m; i++)
        {
            scanf("%d%d%d", &x, &y, &z);
            int l = LCA(x, y);
            t[x] = update(t[x], 1, Z, z, 1);
            t[y] = update(t[y], 1, Z, z, 1);
            t[l] = update(t[l], 1, Z, z, -1);
            if(f[l][1]) t[f[l][1]] = update(t[f[l][1]], 1, Z, z, -1);
        }
        solve(1);
        for(int i = 1; i <= n; i++) printf("%d
    ", ANS[i]);
        return 0;
    }
    
  • 相关阅读:
    java中Map遍历的四种方式
    Java从网络读取图片并保存至本地
    spring整合问题分析之Write operations are not allowed in readonly mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.
    element 中table表格多选,翻页或者切换不同数据后保存之前选择的数据并返显选中的状态
    nvm的安装与使用(Mac 版)
    常用正则表达式
    uniapp开发微信小程序
    关于elementui select组件change事件只要数据变化就会触发的解决办法
    elementui的表单重置方法resetFields()的坑
    Element中vfor动态数据循环表单验证的处理
  • 原文地址:https://www.cnblogs.com/Andy-park/p/13763475.html
Copyright © 2011-2022 走看看