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 ...
随机推荐
- docker教程目录
为什么要用 Docker 什么是 Docker Docker 镜像 Docker容器的运用 Docker仓库 Docker如何获取镜像 CentOS 安装Docker Docker 列出镜像 Dock ...
- iOS中的二维数组
首先我们知道OC中是没有二维数组的,二维数组是通过一位数组的嵌套实现的,但是别忘了我们有字面量,实际上可以和C/C++类似的简洁地创建和使用二维数组.这里总结了创建二维数组的两种方法以及数组的访问方式 ...
- 尽量不要使用using namespace std
C++标准程序库中的所有标识符都被定义于一个名为std的namespace中. namespace是指标识符的各种可见范围.命名空间用关键字namespace 来定义.命名空间是C++的一种机制,用来 ...
- 使用 Vs 2015 快速上手 Angular2
Visual Studio 2015 快速上手(使用Angular2)https://angular.cn/guide/visual-studio-2015 使用 Vs 2015 快速上手 Angul ...
- Java 9的JDK中值得期待的:不仅仅是模块化
在多次延期后,Java 9将于9月21日以Java开发工具包9的形式出现,这是自2014年3月以来,Java标准版的第一次重大升级.官方列出了JDK 9的大约90个新特性,模块化是最主要的一个.将Ja ...
- Android Kotlin —— 语言结合
2017 Google I/O 大会开始就宣布,将Kotlin语言作为安卓开发的一级编程语言. Kotlin 是一个基于 JVM 的新的编程语言,由 JetBrains 开发. Ko ...
- C#/JAVA 程序员转GO/GOLANG程序员笔记大全(DAY 05)
----------------------------------------- error 使用 (异常处理) // 语法 (普通错误) import "errors" fun ...
- Less开发指南(二)- 基本语法
(一)嵌套规则 [1]less可以让我们以嵌套的方式编写层叠样式,先看下面这段CSS: .box-a .hd { height: 20px; } .box-a .bd .txt { color: #0 ...
- EBS Certifications
Last Updated: September 29, 2017. This summary cross-references published blog articles and the off ...
- jquery基础 笔记一
一. 1. vsdoc: 在Visual Studio中需要引入此版本的jquery类库才能启用智能感知.如:jquery-1.3.2-vsdoc2.js<body> <div id ...