LOJ2359. 「NOIP2016」天天爱跑步【树上差分】
思路
首先发现如果对于一个节点,假设一个节点需要统计从字数内来的贡献
需要满足\(dep_u - dep_s = w_u\)
这个条件其实可以转化成\(dep_u - w_u = dep_s\)
然后对于这个东西我们只需要记录下\(dep_s\)的信息就好了
然后考虑差分,把一个询问先分解成\(s->lca\)和\(lca->t\)两部分
接着把连边分别差分处理就可以了
从子树以外的地方的贡献也很好维护
//Author: dream_maker
#include<bits/stdc++.h>
using namespace std;
//----------------------------------------------
//typename
typedef long long ll;
//convenient for
#define fu(a, b, c) for (int a = b; a <= c; ++a)
#define fd(a, b, c) for (int a = b; a >= c; --a)
#define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
//inf of different typename
const int INF_of_int = 1e9;
const ll INF_of_ll = 1e18;
//fast read and write
template <typename T>
void Read(T &x) {
bool w = 1;x = 0;
char c = getchar();
while (!isdigit(c) && c != '-') c = getchar();
if (c == '-') w = 0, c = getchar();
while (isdigit(c)) {
x = (x<<1) + (x<<3) + c -'0';
c = getchar();
}
if (!w) x = -x;
}
template <typename T>
void Write(T x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x > 9) Write(x / 10);
putchar(x % 10 + '0');
}
//----------------------------------------------
const int N = 3e5;
struct Node{
int u, len, typ, dir;
//typ 1:insert -1:erase
//dir 1:up 0:down
};
vector<Node> g[N];
struct Edge{
int v, nxt;
} E[N << 1];
int head[N], tot = 0;
int down[N << 1], up[N << 1];
int Log[N], dep[N], w[N];
int Fa[N][18];
int n, m, ans[N];
void add(int u, int v) {
E[++tot] = (Edge) {v, head[u]};
head[u] = tot;
}
void dfs(int u, int fa) {
dep[u] = dep[fa] + 1;
Fa[u][0] = fa;
fu(i, 1, Log[dep[u]]) Fa[u][i] = Fa[Fa[u][i - 1]][i - 1];
for (int i = head[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (v == fa) continue;
dfs(v, u);
}
}
int Lca(int u, int v) {
if (dep[u] < dep[v]) swap(u, v);
int delta = dep[u] - dep[v];
fu(i, 0, Log[delta])
if ((delta >> i) & 1)
u = Fa[u][i];
if (u == v) return u;
int k = Log[dep[u]];
while (Fa[u][0] != Fa[v][0]) {
if (Fa[u][k] != Fa[v][k]) {
u = Fa[u][k];
v = Fa[v][k];
}
k--;
}
return Fa[u][0];
}
void solve(int u) {
ans[u] -= down[w[u] - dep[u] + N] + up[w[u] + dep[u]];
fv(j, g[u]) {
Node now = g[u][j];
if (now.dir) up[now.len] += now.typ;
else down[now.len] += now.typ;
}
for (int i = head[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (v == Fa[u][0]) continue;
solve(v);
}
ans[u] += down[w[u] - dep[u] + N] + up[w[u] + dep[u]];
}
int main() {
#ifdef dream_maker
freopen("input.txt", "r", stdin);
#endif
Read(n), Read(m);
Log[1] = 0; fu(i, 2, n) Log[i] = Log[i >> 1] + 1;
fu(i, 2, n) {
int u, v;
Read(u), Read(v);
add(u, v);
add(v, u);
}
dfs(1,0);
fu(i, 1, n) Read(w[i]);
fu(i, 1, m) {
int u, v;
Read(u), Read(v);
int lca = Lca(u, v);
g[u].push_back((Node){u, dep[u], 1, 1});
g[Fa[lca][0]].push_back((Node){Fa[lca][0], dep[u], -1, 1});
g[v].push_back((Node){v, dep[u] - 2 * dep[lca] + N, 1, 0});
g[lca].push_back((Node){lca, dep[u] - 2 * dep[lca] + N, -1, 0});
}
solve(1);
fu(i, 1, n) {
Write(ans[i]);
putchar(' ');
}
return 0;
}
LOJ2359. 「NOIP2016」天天爱跑步【树上差分】的更多相关文章
- LOJ #2359. 「NOIP2016」天天爱跑步(倍增+线段树合并)
题意 LOJ #2359. 「NOIP2016」天天爱跑步 题解 考虑把一个玩家的路径 \((x, y)\) 拆成两条,一条是 \(x\) 到 \(lca\) ( \(x, y\) 最近公共祖先) 的 ...
- 「NOIP2016」天天爱跑步 题解
(声明:图片来源于网络) 「NOIP2016」天天爱跑步 题解 题目TP门 题目 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是 ...
- 「NOIP2016」天天爱跑步
传送门 Luogu 解题思路 树上差分+桶计数. 我们发现在一条路径上的点 \(i\) ,它可以观测到玩家的条件是: \(i \in (u \to LCA),dep_u=w_i+dep_i\) \(i ...
- NOIP2016 Day1 T2 天天爱跑步(树上差分,LCA)
原文链接 原题链接 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏 ...
- 洛谷 1600 (NOIp2016) 天天爱跑步——树上差分
题目:https://www.luogu.org/problemnew/show/P1600 看TJ:https://blog.csdn.net/clove_unique/article/detail ...
- 洛谷P1600 天天爱跑步——树上差分
题目:https://www.luogu.org/problemnew/show/P1600 看博客:https://blog.csdn.net/clove_unique/article/detail ...
- 洛谷$P1600$ 天天爱跑步 树上差分
正解:树上差分 解题报告: 传送门$QwQ$! 这题还挺妙的,,,我想了半天才会$kk$ 首先对一条链$S-T$,考虑先将它拆成$S-LCA$和$LCA-T$,分别做.因为总体上来说差不多接下来我就只 ...
- NOIP2016 天天爱跑步 (树上差分+dfs)
题目大意:给你一颗树,树上每个点都有一个观察员,他们仅会在 w[i] 时刻出现,观察正在跑步的玩家 一共有m个玩家,他们分别从节点 s[i] 同时出发,以每秒跑一条边的速度,沿着到 t[i] 的唯一路 ...
- [NOIP2016]天天爱跑步(树上差分+线段树合并)
将每个人跑步的路径拆分成x->lca,lca->y两条路径分别考虑: 对于在点i的观察点,这个人(s->t)能被观察到的充要条件为: 1.直向上的路径:w[i]=dep[s]-dep ...
随机推荐
- python 类和对象的属性
python类和对象的属性分为类属性和对象属性两大类,类属性属于类,而对象属性属于对象. 1. 父类的对象属性会被子类的对象继承. 2. 父类的类属性会被子类继承,还是作为类属性,如果父类改变了类属性 ...
- js 冒泡型事件
- Delphi.format填充0
1. ]);// 一共8位数字不够的补零 2. 3. 4. 5.
- DML,DML,DCL,DQL
可以先看看这篇微博:http://blog.csdn.net/jiben2qingshan/article/details/7832344 http://blog.163.com/chenwenlin ...
- SQL 2008R2还原对于服务器失败 备份集中的数据库与现有数据库 3154错误
以前用sql server 2005的时候就遇到过类似的问题,数据库在别的服务器上备份后,在本机无法还原,这次终于找到了解决方案,网上的没有找到类似的,希望能帮到大家! 原因分析:在SQL Serve ...
- 分布式缓存集群方案特性使用场景(Memcache/Redis(Twemproxy/Codis/Redis-cluster))优缺点对比及选型
分布式缓存集群方案特性使用场景(Memcache/Redis(Twemproxy/Codis/Redis-cluster))优缺点对比及选型 分布式缓存特性: 1) 高性能:当传统数据库面临大规模 ...
- Javascript中的void
原来void是将其后的字面量当元表达式执行,并永远返回undefined.同时undefined不是关键词.. 由于JS表达式偏啰嗦,于是最近便开始采用Coffeescript来减轻负担.举个栗子,当 ...
- STL学习笔记(转,还是比较全的)
STL简介 1 概况 2 1.1 STL是什么 2 1.2 为什么我们需要学习STL 2 1.3 初识STL 2 1.4 STL 的组成 5 2 容器 6 2.1 基本容器——向量(vector) 6 ...
- Windows 下配置Git
在Windows上安装git很长时间了,一直都没有配置,就是简单的使用.当然配置后就可以在任意目录下使用git命令.其实就是配置下git的环境变量. 首先,当然下载windows版本:点我下载 安装直 ...
- Disruptor快速入门
在JDK的多线程与并发库一文中, 提到了BlockingQueue实现了生产者-消费者模型 BlockingQueue是基于锁实现的, 而锁的效率通常较低. 有没有使用CAS机制实现的生产者-消费者? ...