天天爱跑步【树上差分】
题目链接
很好的一道题目,主要是要想到这个方向。
首先,很容易想到的是,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;
}
天天爱跑步【树上差分】相关推荐
- [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 • 给出一棵二叉树,每个点有点权 ?? • 如果 ? 在 ? 的左(右)子树中,且 ? 到 ? 的距离为 ??,则称 ? 为 ? 的左(右)关联点 • 求每个点的左.右关 ...
- BZOJ 4719--天天爱跑步(LCA差分)
4719: [Noip2016]天天爱跑步 Time Limit: 40 Sec Memory Limit: 512 MB Submit: 1464 Solved: 490 [Submit][St ...
- [NOIP2016]天天爱跑步 题解(树上差分) (码长短跑的快)
Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务.这个游戏的地图 ...
- P1600-天天爱跑步【LCA,桶,树上差分】
正题 题目链接:https://www.luogu.org/problemnew/show/P1600 题目大意 一棵nnn个点的树,通过每条边需要时间为1.有mmm个玩家从SiS_iSi跑到TiT ...
- 【NOIP2016】【桶/线段树合并】【树上差分】天天爱跑步
[题目描述] [思路] 这是道好题呀.考虑把一条路径(u,v)拆成两条:从u到lca(u,v),从lca(u,v)到v.下面我们以向上的路径为例讨论做法.对于一条向上的路径,它对一个点x有贡献当且仅当 ...
- NOIP2016天天爱跑步 题解报告【lca+树上统计(桶)】
题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nn个 ...
- NOIP2016天天爱跑步
NOIP2016天天爱跑步 这题一看显然lca+树上差分,但是因为有w的限制不能直接加,所以考虑权值线段树合并, 每个选手的起点终点对于不同的节点的影响是不同的,这就非常麻烦了,但是可以发现无论如何他 ...
- 差分数组 and 树上差分
差分数组 定义 百度百科中的差分定义 //其实这完全和要讲的没关系 qwq 进去看了之后是不是觉得看不懂? 那我简单概括一下qwq 差分数组de定义:记录当前位置的数与上一位置的数的差值. 栗子 容易 ...
- P1600 天天爱跑步
P1600 天天爱跑步 题目描述 详见:P1600 天天爱跑步 Solution 树上差分+LCA. Code #include<bits/stdc++.h> using namespac ...
最新文章
- Web GIS离线解决方案
- ImageMagick常用指令详解
- ansible加密敏感数据
- K8S 部署 ingress-nginx (三) 启用 https
- JVM垃圾回收机制总结(3) :按代垃圾收集器
- 不需要密码的windows计划任务设置
- shell sort
- android:configchanges的作用,将uiMode附加到android:configChanges实际做什么?
- 【ES6-11(2015-2020)】特性总览与开发环境准备
- js实现给数字加三位一逗号间隔的两种方法
- 【译】《Pro ASP.NET MVC4 4th Edition》第三章(二)
- 菊长说丨一文读懂MySQL4种事务隔离级别
- Arcface 总结
- 在电脑上如何快速制作一寸照片?在线一键制作工具推荐给你
- springboot学习笔记1——springboot初始化
- LINUX未来的发展前景
- SAP中Exchange rate type EURX到底干嘛用的
- 苹果电脑怎么打开计算机管理,mac打开的软件怎么关 苹果电脑系统怎么关闭打开的程序...
- 虚拟桌面基础架构 (VDI)及其工作原理
- 非线性光学散射偏微分方程组的matlab求解仿真