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;
}
原文地址:https://www.cnblogs.com/zbr162/p/11822661.html