zoukankan      html  css  js  c++  java
  • 运输 [树上差分, 整除分块]

    运输



    color{red}{正解部分}

    树上差分 + 整除分块

    对询问 (x,y,w)(x, y, w), 在 x,yx, y 处计算 x,yx, y 到根节点路径上 ww 的贡献, 再在 lcalca 处减去多计算的贡献,

    ww 走过一条边 edgeedge 对答案的贡献为 edge.w1wlfloor frac{edge.w-1}{w} floor, 其取值只有 O(3×104)O(sqrt{3 imes 10^4}) 种,

    所以考虑 离线 所有询问, 在 DFSDFS 走过 边 edgeedge 时, 整除分块 处理出 [1,edge.w][1, edge.w] 内所有取值, 在 树状数组区间修改,

    回溯时同上进行撤销操作, 在当前点计算所有关于该点的询问即可 .


    color{red}{实现部分}

    #include<bits/stdc++.h>
    #define reg register
    #define pb push_back
    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 = 1e5 + 10;
    
    int N;
    int M;
    int num0;
    int dep[maxn];
    int fuck[maxn];
    int head[maxn];
    int Fk[maxn][20];
    
    ll Ans[maxn];
    
    struct Que{ int x, y; } ;
    
    std::vector <Que> A[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(int k, int fa){
            dep[k] = dep[fa] + 1;
            for(reg int i = 1; i <= 19; i ++) Fk[k][i] = Fk[Fk[k][i-1]][i-1];
            for(reg int i = head[k]; i; i = edge[i].nxt){
                    int to = edge[i].to;
                    if(to == fa) continue ;
                    Fk[to][0] = k; DFS(to, k);
            }
    }
    
    int Lca(int x, int y){
            if(dep[x] < dep[y]) std::swap(x, y);
            for(reg int i = 19; i >= 0; i --)
                    if(dep[Fk[x][i]] >= dep[y]) x = Fk[x][i];
            if(x == y) return x;
            for(reg int i = 19; i >= 0; i --)
                    if(Fk[x][i] != Fk[y][i]) x = Fk[x][i], y = Fk[y][i];
            return Fk[x][0];
    }
    
    void init(int i){
            int x  = read(), y = read(); fuck[i] = read();
            A[x].pb((Que){ i, 1 }), A[y].pb((Que){ i, 1 });
            int lca = Lca(x, y); A[lca].pb((Que){ i, -2 });
            Ans[i] = dep[x] + dep[y] - 2*dep[lca] + 1;
    }
    
    struct Bit_Tree{
    
            int lim;
            ll d[maxn], d2[maxn];
    
            void Add(int k, ll x){ for(reg int i = k; i <= lim; i += (i&-i)) d[i] += x, d2[i] += 1ll*x*k; }
    
            ll Ask(int k){
                    if(k <= 0) return 0;
                    ll s = 0;
                    for(reg int i = k; i; i -= (i&-i)) s += (1ll*k+1)*d[i] - d2[i];
                    return s;
            }
    
            void modify(const int &l, const int &r, const ll &x){ Add(l, x), Add(r+1, -x); }
    
            ll query(const int &l, const int &r){ return Ask(r) - Ask(l-1); }
    
    } bit_t;
    
    void DFS_2(int k, int fa){
            fa --;
            for(reg int l = 1, r = 0; l <= fa; l = r+1){
                    r = fa/(fa/l);
                    bit_t.modify(l, r, fa/l);
            }
            int size = A[k].size();
            for(reg int i = 0; i < size; i ++){
                    int id = A[k][i].x, opt = A[k][i].y;
                    Ans[id] += opt * bit_t.query(fuck[id], fuck[id]);
            }
            for(reg int i = head[k]; i; i = edge[i].nxt){
                    int to = edge[i].to;
                    if(to == Fk[k][0]) continue ;
                    DFS_2(to, edge[i].w);
            }
            for(reg int l = 1, r = 0; l <= fa; l = r+1){
                    r = fa/(fa/l);
                    bit_t.modify(l, r, -fa/l);
            }
    }
    
    int main(){
            N = read(), M = read();
            for(reg int i = 1; i < N; i ++){
                    int u = read(), v = read(), d = read();
                    Add(u, v, d), Add(v, u, d);
            }
            DFS(1, 0);
            for(reg int i = 1; i <= M; i ++) init(i);
            bit_t.lim = 30000; DFS_2(1, 0);
            for(reg int i = 1; i <= M; i ++) printf("%lld
    ", Ans[i]);
            return 0;
    }
    
  • 相关阅读:
    越大优先级越高,优先级越高被OS选中的可能性就越大
    锁标记如果过多,就会出现线程等待其他线程释放锁标记
    使用带缓冲区的输入输出流的速度会大幅提高
    Bufferread有readline()使得字符输入更加方便
    java的开发主要以http为基础
    UDP也需要现有Server端,然后再有Client端
    端口是一种抽象的软件结构,与协议相关
    具有全球唯一性,相对于internet,IP为逻辑地址
    判断是否一个属性或对象可序列化
    把对象通过流序列化到某一个持久性介质称为对象的可持久化
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822395.html
Copyright © 2011-2022 走看看