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;
    }
    
  • 相关阅读:
    20182330 2019-2020-1 《数据结构与面向对象程序设计》实验四报告
    20182330 2019-2020-1 《数据结构与面向对象程序设计》第四周学习总结
    20182330 2019-2020-1 《数据结构与面向对象程序设计》实验三报告
    20182330 2019-2020-1 《数据结构与面向对象程序设计》第三周学习总结
    20182330 2019-2020-1 《数据结构与面向对象程序设计》实验二报告
    20182330 2019-2020-1 《数据结构与面向对象程序设计》实验一报告
    20182330 2019-2020-1《数据结构与面向对象程序设计》第一周学习总结
    20182326 2019-2020-1 《数据结构与面向对象程序设计》实验六报告
    20182326 2019-2020-1 《数据结构与面向对象程序设计》实验五报告
    2019-2020-26 《数据结构与面向对象程序设计》第6周学习总结
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822661.html
Copyright © 2011-2022 走看看