运输 [树上差分, 整除分块]

运 输 运输



正 解 部 分 \color{red}{正解部分}

树 上 差 分 树上差分 + 整 除 分 块 整除分块

对询问 ( x , y , w ) (x, y, w) (x,y,w), 在 x , y x, y x,y 处计算 x , y x, y x,y 到根节点路径上 w w w 的贡献, 再在 l c a lca lca 处减去多计算的贡献,

w w w 走过一条边 e d g e edge edge 对答案的贡献为 ⌊ e d g e . w − 1 w ⌋ \lfloor \frac{edge.w-1}{w} \rfloor wedge.w1, 其取值只有 O ( 3 × 1 0 4 ) O(\sqrt{3\times 10^4}) O(3×104 ) 种,

所以考虑 离线 所有询问, 在 D F S DFS DFS 走过 边 e d g e edge edge 时, 整除分块 处理出 [ 1 , e d g e . w ] [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\n", Ans[i]);
        return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值