zoukankan      html  css  js  c++  java
  • 三只企鹅 [重链剖分]

    三只企鹅


    color{red}{正解部分}

    若对 {pi}{p_i} 进行了修改, 总共修改了 kk 次, 此时若询问 xx, 则答案为 ans=deppi+kdepx2deplca(pi,x)ans = sum dep_{p_i} + k dep_x - 2sum dep_{lca(p_i,x)} .

    考虑维护 2deplca(pi,x)2sum dep_{lca(p_i,x)},

    • 修改 xx, 将 xx 到根节点路径上的每个点的标记加上对应的 depdep .
    • 询问 xx, 将 xx 到根节点路径上的标记求和, 按上式计算即可 .

    使用 树剖 维护 .


    color{red}{实现部分}

    • 注意树链剖分维护的东西必须以 dfsdfs序 为下标 .
    #include<bits/stdc++.h>
    #define reg register
    typedef long long ll;
    
    int read(){
            char c;
            int s = 0, flag = 1;
            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;
    }
    
    const int maxn = 200005;
    
    int N;
    int M;
    int num0;
    int dftim;
    int Fa[maxn];
    int top[maxn];
    int dfn[maxn];
    int son[maxn];
    int size[maxn];
    int head[maxn];
    
    ll Tmp_1;
    ll Tmp_2;
    ll dis[maxn];
    ll fuck[maxn];
    ll fa_w[maxn];
    
    struct Edge{ int nxt, to, w; } edge[maxn << 1];
    
    void Add(int from, int to, int w){ edge[++ num0] = (Edge){ head[from], to, w }; head[from] = num0; }
    
    void DFS_1(int k, int fa){
            size[k] = 1, Fa[k] = fa;
            for(reg int i = head[k]; i; i = edge[i].nxt){
                    int to = edge[i].to;
                    if(to == fa) continue ;
                    dis[to] = dis[k] + edge[i].w, fa_w[to] = edge[i].w;
                    DFS_1(to, k); size[k] += size[to];
                    if(size[son[k]] < size[to]) son[k] = to;
            }
    }
    
    void DFS_2(int k, int tp){
            dfn[k] = ++ dftim, top[k] = tp;
            if(son[k]) DFS_2(son[k], tp);
            fuck[dfn[son[k]]] = fa_w[son[k]];
            for(reg int i = head[k]; i; i = edge[i].nxt){
                    int to = edge[i].to;
                    if(to == son[k] || to == Fa[k]) continue ;
                    DFS_2(to, to);
                    fuck[dfn[to]] = fa_w[to];
            }
    }
    
    struct Segment_Tree{
    
            struct Node{ int l, r; ll s, w, tg; } T[maxn << 2];
    
            void Build(int k, int l, int r){
                    T[k].l = l, T[k].r = r;
                    if(l == r) return T[k].s = fuck[l], void();
                    int mid = l+r >> 1;
                    Build(k<<1, l, mid), Build(k<<1|1, mid+1, r);
                    T[k].s = T[k<<1].s + T[k<<1|1].s;
            }
    
            void Push_down(const int &k){
                    T[k].w += T[k].s * T[k].tg;
                    if(T[k].l == T[k].r) return T[k].tg = 0, void();
                    T[k<<1].tg += T[k].tg, T[k<<1|1].tg += T[k].tg;
                    T[k].tg = 0;
            }
    
            void Push_up(const int &k){ T[k].w = (T[k<<1].w + T[k<<1|1].w); }
    
            void Modify(int k, const int &ql, const int &qr, const int &aim){
                    int l = T[k].l, r = T[k].r;
                    if(T[k].tg) Push_down(k);
                    if(r < ql || l > qr) return ;
                    if(ql <= l && r <= qr) return T[k].tg += aim, Push_down(k), void();
                    Modify(k<<1, ql, qr, aim), Modify(k<<1|1, ql, qr, aim); Push_up(k);
            }
    
            ll Query(int k, const int &ql, const int &qr){
                    int l = T[k].l, r = T[k].r;
                    if(T[k].tg) Push_down(k);
                    if(r < ql || l > qr) return 0;
                    if(ql <= l && r <= qr) return T[k].w;
                    return Query(k<<1, ql, qr) + Query(k<<1|1, ql, qr);
            }
    
    } seg_t;
    
    void modify(int k){ while(k) seg_t.Modify(1, dfn[top[k]], dfn[k], 1), k = Fa[top[k]]; }
    
    ll query(int k){ ll s = 0; while(k) s += seg_t.Query(1, dfn[top[k]], dfn[k]), k = Fa[top[k]]; return s; }
    
    int main(){
            N = read(), M = read();
            for(reg int i = 1; i < N; i ++){
                    int u = read(), v = read(), w = read();
                    Add(u, v, w), Add(v, u, w);   
            }
            DFS_1(1, 0); DFS_2(1, 1), seg_t.Build(1, 1, N);
            while(M --){
                    int opt = read(), x = read();
                    if(opt == 1) modify(x), Tmp_1 += dis[x], Tmp_2 ++;
                    else printf("%lld
    ", Tmp_1 + Tmp_2*dis[x] - 2ll*query(x));
            }
            return 0;
    }
    
  • 相关阅读:
    微信公众平台开发(6) 微信退款接口
    shiro 认证和授权原理
    Shiro架构
    微信公众平台开发(5) 微信客服消息接口
    微信公众平台开发(4) 微信模板消息接口
    微信公众平台开发(3) 企业付款
    微信公众平台开发(1) 通用的工具类CommonUtil
    spring 源码构建
    springMvc配置拦截器无效
    IIdea使用CXF开发WebService
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822406.html
Copyright © 2011-2022 走看看