题目链接


很好的一道题目,主要是要想到这个方向。

首先,很容易想到的是,S到T的路径可以拆分成S~LCA和LCA~T这两条,现在,我们假设有一个点x满足条件,那么可以列出怎样的恒等式呢?

表示x到S的路径长度为W[x]。这样说明的是到S的,是S~LCA这条链上的,但是换成LCA~T那条链上的话呢,那又是怎样?

,意味着我们走到LCA的剩余时间再走到x,将上面两个式子化简一下,我们可以得到:

(等式一)

(等式二)

我们可以发现等式的左边就是一个恒值,不变值。统计答案可以通过统计等式右边的值来得到,于是,我们可以在树上维护左边的值,查询的时候只需要查询该子树下右边的值的个数即可。

主要的思维就是在这了,其余的部分就不是太难处理了,可以利用差分的方式来解决问题。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 3e5 + 7;
int N, M, head[maxN], cnt, deep[maxN], root[maxN][20], LOG2[maxN], W[maxN];
struct Eddge
{int nex, to;Eddge(int a=-1, int b=0):nex(a), to(b) {}
}edge[maxN << 1];
inline void addEddge(int u, int v)
{edge[cnt] = Eddge(head[u], v);head[u] = cnt++;
}
inline void _add(int u, int v) { addEddge(u, v); addEddge(v, u); }
void pre_dfs(int u, int fa)
{root[u][0] = fa; deep[u] = deep[fa] + 1;for(int i=0; i<LOG2[N]; i++) root[u][i + 1] = root[root[u][i]][i];for(int i=head[u], v; ~i; i=edge[i].nex){v = edge[i].to;if(v == fa) continue;pre_dfs(v, u);}
}
inline int LCA(int u, int v)
{if(deep[u] < deep[v]) swap(u, v);int det = deep[u] - deep[v];for(int i=LOG2[det]; i>=0; i--) if((det >> i) & 1) u = root[u][i];if(u == v) return u;for(int i=LOG2[N]; i>=0; i--){if(root[u][i] ^ root[v][i]){u = root[u][i];v = root[v][i];}}return root[u][0];
}
vector<int> delt[maxN], put_in[maxN], redelt[maxN];
int s1[maxN << 1] = {0}, sum[maxN] = {0}, ans[maxN] = {0};
void dfs_1(int u, int fa)
{int old = s1[deep[u] + W[u]];for(int i=head[u], v; ~i; i=edge[i].nex){v = edge[i].to;if(v == fa) continue;dfs_1(v, u);}s1[deep[u]] += sum[u];ans[u] += s1[deep[u] + W[u]] - old;for(auto x : delt[u]){if(deep[x] - deep[u] == W[u]) ans[u]--; //之后还会被算一遍s1[deep[x]] --;}
}
unordered_map<int, int> s2;
void dfs_2(int u, int fa)
{int old = s2[deep[u] - W[u]];for(int i=head[u], v; ~i; i=edge[i].nex){v = edge[i].to;if(v == fa) continue;dfs_2(v, u);}for(auto x : put_in[u]){s2[x] ++;}ans[u] += s2[deep[u] - W[u]] - old;for(auto x : redelt[u]){s2[x] --;}
}
inline void init()
{cnt = 0;for(int i=1; i<=N; i++) head[i] = -1;for(int i=1, j = 2, k = 0; i < maxN; i++){if(i == j) { k++; j <<= 1; }LOG2[i] = k;}
}
int main()
{scanf("%d%d", &N, &M);init();for(int i=1, u, v; i<N; i++){scanf("%d%d", &u, &v);_add(u, v);}deep[0] = 0;pre_dfs(1, 0);for(int i=1; i<=N; i++) scanf("%d", &W[i]);for(int i=1, Si, Ti, _lca; i<=M; i++){scanf("%d%d", &Si, &Ti);_lca = LCA(Si, Ti);sum[Si]++; delt[_lca].push_back(Si);put_in[Ti].push_back(2 * deep[_lca] - deep[Si]);redelt[_lca].push_back(2 * deep[_lca] - deep[Si]);}dfs_1(1, 0);dfs_2(1, 0);for(int i=1; i<=N; i++) printf("%d%c", ans[i], i == N ? '\n' : ' ');return 0;
}

天天爱跑步【树上差分】相关推荐

  1. [NOIP2016 提高组] 天天爱跑步(树上差分)

    如果没有时间的限制,这题就是对每个点iii,求经过iii的路径数,用树上差分解决即可: 枚举路径x→y{x\to y\{x→y{ a[x]+=1;a[y]+=1;a[x]+=1;a[y]+=1;a[x ...

  2. 天天爱跑步——树上差分

    先来一道简化版: 关联点 2 • 给出一棵二叉树,每个点有点权 ?? • 如果 ? 在 ? 的左(右)子树中,且 ? 到 ? 的距离为 ??,则称 ? 为 ? 的左(右)关联点 • 求每个点的左.右关 ...

  3. BZOJ 4719--天天爱跑步(LCA差分)

    4719: [Noip2016]天天爱跑步 Time Limit: 40 Sec  Memory Limit: 512 MB Submit: 1464  Solved: 490 [Submit][St ...

  4. [NOIP2016]天天爱跑步 题解(树上差分) (码长短跑的快)

    Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务.这个游戏的地图 ...

  5. P1600-天天爱跑步【LCA,桶,树上差分】

    正题 题目链接:https://www.luogu.org/problemnew/show/P1600 题目大意 一棵nnn个点的树,通过每条边需要时间为1.有mmm个玩家从SiS_iSi​跑到TiT ...

  6. 【NOIP2016】【桶/线段树合并】【树上差分】天天爱跑步

    [题目描述] [思路] 这是道好题呀.考虑把一条路径(u,v)拆成两条:从u到lca(u,v),从lca(u,v)到v.下面我们以向上的路径为例讨论做法.对于一条向上的路径,它对一个点x有贡献当且仅当 ...

  7. NOIP2016天天爱跑步 题解报告【lca+树上统计(桶)】

    题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nn个 ...

  8. NOIP2016天天爱跑步

    NOIP2016天天爱跑步 这题一看显然lca+树上差分,但是因为有w的限制不能直接加,所以考虑权值线段树合并, 每个选手的起点终点对于不同的节点的影响是不同的,这就非常麻烦了,但是可以发现无论如何他 ...

  9. 差分数组 and 树上差分

    差分数组 定义 百度百科中的差分定义 //其实这完全和要讲的没关系 qwq 进去看了之后是不是觉得看不懂? 那我简单概括一下qwq 差分数组de定义:记录当前位置的数与上一位置的数的差值. 栗子 容易 ...

  10. P1600 天天爱跑步

    P1600 天天爱跑步 题目描述 详见:P1600 天天爱跑步 Solution 树上差分+LCA. Code #include<bits/stdc++.h> using namespac ...

最新文章

  1. Web GIS离线解决方案
  2. ImageMagick常用指令详解
  3. ansible加密敏感数据
  4. K8S 部署 ingress-nginx (三) 启用 https
  5. JVM垃圾回收机制总结(3) :按代垃圾收集器
  6. 不需要密码的windows计划任务设置
  7. shell sort
  8. android:configchanges的作用,将uiMode附加到android:configChanges实际做什么?
  9. 【ES6-11(2015-2020)】特性总览与开发环境准备
  10. js实现给数字加三位一逗号间隔的两种方法
  11. 【译】《Pro ASP.NET MVC4 4th Edition》第三章(二)
  12. 菊长说丨一文读懂MySQL4种事务隔离级别
  13. Arcface 总结
  14. 在电脑上如何快速制作一寸照片?在线一键制作工具推荐给你
  15. springboot学习笔记1——springboot初始化
  16. LINUX未来的发展前景
  17. SAP中Exchange rate type EURX到底干嘛用的
  18. 苹果电脑怎么打开计算机管理,mac打开的软件怎么关 苹果电脑系统怎么关闭打开的程序...
  19. 虚拟桌面基础架构 (VDI)及其工作原理
  20. 非线性光学散射偏微分方程组的matlab求解仿真

热门文章

  1. 2023年特斯拉新能源汽车核心部件解密
  2. 主动保护——ACS汽车防撞安全保护器
  3. 外汇投资:速交易合法吗?如何选择正规的交易平台?
  4. 什么是导航与位置服务器,GPS导航和GPS定位仪与GPS定位器的区别在哪?
  5. 柏拉图与苏格拉底经典对话
  6. 航运船公司人工智能AI产品成熟化标准化规模应用,全球港航人工智能/集装箱人工智能领军者CIMC中集飞瞳,打造国际航运智能化标杆
  7. android开发每日汇总【2011-10-14】
  8. 一文读懂朴素贝叶斯分类算法
  9. websocket中的心跳重连机制
  10. 爱奇艺2020校招Java方向笔试题(第一场)