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 ...
随机推荐
- WPF圆角透明无边框窗体
<Window x:Class="ImportData.MainWindow" xmlns="http://schemas.microsoft.com/winfx/ ...
- NPM Scripts -- onchange parallelshell
Watch for changes to the styles.scss file and automatically compile it to the css file. Run multiple ...
- 讲一下numpy的矩阵特征值分解与奇异值分解
1.特征值分解 主要还是调包: from numpy.linalg import eig 特征值分解: A = P*B*PT 当然也可以写成 A = QT*B*Q 其中B为对角元为A的特征值的对 ...
- .net core mvc部署到IIS导出Word 提示80070005拒绝访问
项目中相信大家经常会遇到导出Word.Excel等需求,在实际开发环境中,一般不会出现什么问题,但当发布到IIS上后可能会遇到各种各样的问题,一般都是权限的问题.前几天把公司项目发布后,出现Word导 ...
- linux五大搜索命令学习
五大搜索命令学习 分别解释locate,find,which,whereis,grep 五大linux搜索命令 locate 解释:由man手册可以看出,locate查找就是根据文件名进行查找,只是依 ...
- Java解析XML格式串(JDOM解析)
import java.io.IOException; import java.io.StringReader; import java.util.List; import org.jdom.Docu ...
- @Primary-在spring中常被忽视的注解
在spring 中使用注解,常使用@Autowired, 默认是根据类型Type来自动注入的.但有些特殊情况,对同一个接口,可能会有几种不同的实现类,而默认只会采取其中一种的情况下 @Primary ...
- NC 工具的使用教程
NC工具的使用说明...nc使用说明 参数介绍: nc.exe -h即可看到各参数的使用方法. 基本格式:nc [-options] hostname port[s] [ports] ... nc - ...
- IOS-小技巧总结,绝对有你想要的
1.App名称的修改 许多个人开发者或许会有和我一样的经历,开发一个App途中会想到更合适的名字,这时候变会修改工程名以达到App名称改变的目的,其实你可以一步到位—— 在info.plist中添加一 ...
- iOS-不用微信SDK唤起微信支付
作者:TianBai 原文链接:http://www.jianshu.com/p/8930b4496023 要想知道微信SDK是如何调起微信客户端,那么咱们先看看微信SDK到底做了什么 前期准备 接入 ...