zoukankan      html  css  js  c++  java
  • P4556 雨天的尾巴 [树上差分, 树链剖分]

    链接

    雨天的尾巴


    题目描述

    给出一棵NN个结点的树,
    MM次修改操作, 每次操作要求将a,ba,b之间最短路径所有点加上类型为cc的粮食11次,
    到最后输出每个点所储存的最多的粮食类型, 如果有相等数量的, 则输出类型编号最小的.

    N,M,c<=105N, M, c <= 10^5


    整体使用 setset 维护, 会发现由于左儿子对右儿子的影响难以消除, 于是学习了以下方法

    Solution:++线Solution: 树上差分 + 树链剖分 +权值线段树

    若只维护一个线性的序列,
    假如要将a,ba, b之间加cc类型11个, 即为aa位置cc种类加11, b+1b+1位置cc种类减11,
    对每个位置开动态数组记录 差分操作, 最后遍历时用 权值线段树 维护出现次数最多的类型即可

    当其放在了 树 上时, 可以对 a,ba, b 使用树剖中的 ModifyModifyvectorvector 标记差分操作
    可以发现很神奇的一点是:
    由于每条重链上的编号是连续的, 这样相当于将一次修改操作变为logNlogN个分段修改操作, 可以使得dfndfn数组变得像线性序列一样可以一遍遍历得到答案

    于是最后从dfsdfs序为11开始遍历, 权值线段树扫一遍即可

    复杂度 O(Mlog2N+Nlog2c)O(M*log^2N + N*log^2c)
    O(Nlog2N)O(N*log^2N)


    Code

    #include<bits/stdc++.h>
    #define reg register
    #define pb push_back
    
    const int maxn = 100005;
    
    int read(){
            int s = 0, flag = 1;
            char c;
            while((c=getchar()) && !isdigit(c))
                    if(c == '-'){ flag = -1, c = getchar(); break ; }
            while(isdigit(c)) s = s*10 + c-'0', c = getchar();
            return s * flag;        
    }
    
    int N;
    int M;
    int num0;
    int Lim;
    int tim;
    int Mp[maxn];
    int dfn[maxn];
    int top[maxn];
    int max_son[maxn];
    int dep[maxn];
    int Fa[maxn];
    int head[maxn];
    int size[maxn];
    int Ans[maxn];
    std::vector <int> que[maxn];
    
    struct Node{
            int l, r, maxx, mp;
    } T[maxn << 2];
    
    struct Edge{
            int nxt, to;
    } edge[maxn << 1];
    
    void Add(int from, int to){
            edge[++ num0] = (Edge){ head[from], to };
            head[from] = num0;
    }
    
    void DFS_1(int k, int fa){
            size[k] = 1;
            int maxx = 0;
            for(reg int i = head[k]; i; i = edge[i].nxt){
                    int to = edge[i].to;
                    if(to == fa) continue ;
                    DFS_1(to, k);
                    if(size[to] > maxx) maxx = size[to], max_son[k] = to;
                    size[k] += size[to];
            }
    }
    
    void DFS_2(int k, int Top){      //~
            dfn[k] = ++ tim;
            top[k] = Top;
            Mp[tim] = k;
            if(max_son[k]){
                    Fa[max_son[k]] = k;
                    dep[max_son[k]] = dep[k] + 1;
                    DFS_2(max_son[k], Top);
            }
            for(reg int i = head[k]; i; i = edge[i].nxt){
                    int to = edge[i].to;
                    if(dfn[to]) continue ;
                    dep[to] = dep[k] + 1;
                    Fa[to] = k;
                    DFS_2(to, to);
            }
    }
    
    void Modify(int x, int y, int w){
            while(top[x] != top[y]){
                    if(dep[top[x]] < dep[top[y]]) std::swap(x, y);
                    que[dfn[top[x]]].pb(w), que[dfn[x] + 1].pb(-w);
                    x = Fa[top[x]];
            }
            if(dep[x] < dep[y]) std::swap(x, y);
            que[dfn[y]].pb(w), que[dfn[x] + 1].pb(-w);
    }
    
    void Build(int k, int l, int r){
            T[k].l = l, T[k].r = r;
            if(l == r) return ;
            int mid = l+r >> 1;
            Build(k<<1, l, mid), Build(k<<1|1, mid+1, r);
    }
    
    void Push_up(int k){
            T[k].maxx = std::max(T[k<<1].maxx, T[k<<1|1].maxx);
            Node lt = T[k<<1], rt = T[k<<1|1];
            if(lt.maxx > rt.maxx) T[k].mp = lt.mp;
            else if(lt.maxx == rt.maxx) T[k].mp = std::min(lt.mp, rt.mp);
            else T[k].mp = rt.mp;
    }
    
    void Modify_2(int v, int opt, int k){
            int l = T[k].l, r = T[k].r;
            if(l == r){
                    T[k].maxx += opt, T[k].mp = l;
                    return ;
            }
            int mid = l+r >> 1;
            if(v <= mid) Modify_2(v, opt, k<<1);
            else Modify_2(v, opt, k<<1|1);
            Push_up(k);
    }
    
    int main(){
            N = read(), M = read();
            for(reg int i = 1; i < N; i ++){
                    int a = read(), b = read();
                    Add(a, b), Add(b, a);
            }
            DFS_1(1, 0), DFS_2(1, 1);
            for(reg int i = 1; i <= M; i ++){
                    int a = read(), b = read(), c = read();
                    Lim = std::max(Lim, c);
                    Modify(a, b, c);
            }
            Build(1, 1, Lim);
            for(reg int i = 1; i <= N; i ++){
                    for(reg int j = 0; j < que[i].size(); j ++)
                            Modify_2(abs(que[i][j]), que[i][j]/abs(que[i][j]), 1);
                    Ans[Mp[i]] = T[1].mp;
            }
            for(reg int i = 1; i <= N; i ++) printf("%d
    ", Ans[i]);        
            return 0;
    }
    
  • 相关阅读:
    Construct Binary Tree from Preorder and Inorder Traversal
    Construct Binary Tree from Inorder and Postorder Traversal
    Maximum Depth of Binary Tree
    Sharepoint 2013 创建TimeJob 自动发送邮件
    IE8 不能够在Sharepoint平台上在线打开Office文档解决方案
    TFS安装与管理
    局域网通过IP查看对方计算机名,通过计算机名查看对方IP以及查看在线所有电脑IP
    JS 隐藏Sharepoint中List Item View页面的某一个字段
    SharePoint Calculated Column Formulas & Functions
    JS 两个一组数组转二维数组
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822660.html
Copyright © 2011-2022 走看看