LINK


思路

首先发现如果对于一个节点,假设一个节点需要统计从字数内来的贡献

需要满足\(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」天天爱跑步【树上差分】的更多相关文章

  1. LOJ #2359. 「NOIP2016」天天爱跑步(倍增+线段树合并)

    题意 LOJ #2359. 「NOIP2016」天天爱跑步 题解 考虑把一个玩家的路径 \((x, y)\) 拆成两条,一条是 \(x\) 到 \(lca\) ( \(x, y\) 最近公共祖先) 的 ...

  2. 「NOIP2016」天天爱跑步 题解

    (声明:图片来源于网络) 「NOIP2016」天天爱跑步 题解 题目TP门 题目 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是 ...

  3. 「NOIP2016」天天爱跑步

    传送门 Luogu 解题思路 树上差分+桶计数. 我们发现在一条路径上的点 \(i\) ,它可以观测到玩家的条件是: \(i \in (u \to LCA),dep_u=w_i+dep_i\) \(i ...

  4. NOIP2016 Day1 T2 天天爱跑步(树上差分,LCA)

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

  5. 洛谷 1600 (NOIp2016) 天天爱跑步——树上差分

    题目:https://www.luogu.org/problemnew/show/P1600 看TJ:https://blog.csdn.net/clove_unique/article/detail ...

  6. 洛谷P1600 天天爱跑步——树上差分

    题目:https://www.luogu.org/problemnew/show/P1600 看博客:https://blog.csdn.net/clove_unique/article/detail ...

  7. 洛谷$P1600$ 天天爱跑步 树上差分

    正解:树上差分 解题报告: 传送门$QwQ$! 这题还挺妙的,,,我想了半天才会$kk$ 首先对一条链$S-T$,考虑先将它拆成$S-LCA$和$LCA-T$,分别做.因为总体上来说差不多接下来我就只 ...

  8. NOIP2016 天天爱跑步 (树上差分+dfs)

    题目大意:给你一颗树,树上每个点都有一个观察员,他们仅会在 w[i] 时刻出现,观察正在跑步的玩家 一共有m个玩家,他们分别从节点 s[i] 同时出发,以每秒跑一条边的速度,沿着到 t[i] 的唯一路 ...

  9. [NOIP2016]天天爱跑步(树上差分+线段树合并)

    将每个人跑步的路径拆分成x->lca,lca->y两条路径分别考虑: 对于在点i的观察点,这个人(s->t)能被观察到的充要条件为: 1.直向上的路径:w[i]=dep[s]-dep ...

随机推荐

  1. Ubuntu+apache安装redmin

    公司要迁移redmin,本来以为是一个很简单的项目,想不到整整搞了一天加一个晚上. 首先是对ruby的安装不熟悉,现在明白了ruby的安装顺序是先安装rvm版本管理,然后用rvm安装ruby,安装好后 ...

  2. jquery tmpl模板

    之前用模板渲染都是用angular,无意间发现了jquery tmpl这种轻量级,其文档在这里 官方解释对该插件的说明:将匹配的第一个元素作为模板,render指定的数据,签名如下: .tmpl([d ...

  3. NSMutableString和NSString区别,及相互转换方法

    NSString是一个不可变的字符串对象.这不是表示这个对象声明的变量的值不可变,而是表示它初始化以后,你不能改变该变量所分配的内存中的值,但你可以重新分配该变量所处的内存空间.而NSMutableS ...

  4. IdentityServer4在Asp.Net Core中的应用(二)

    继续上次授权的内容,客户端模式后我们再说以下密码模式,先回顾下密码模式的流程: 我们还是使用上次的代码,在那基础上修改,在IdentityServer4里面有一个IdentityServer4.Tes ...

  5. ubuntu 16.04网速监控脚本

    #!/bin/bashif [ $# -ne 1 ];thendev="enp2s0"elsedev=$1fi while :doRX1=`/sbin/ifconfig $dev ...

  6. 19.并发容器之BlockingQueue

    1. BlockingQueue简介 在实际编程中,会经常使用到JDK中Collection集合框架中的各种容器类如实现List,Map,Queue接口的容器类,但是这些容器类基本上不是线程安全的,除 ...

  7. 二十 Python分布式爬虫打造搜索引擎Scrapy精讲—编写spiders爬虫文件循环抓取内容—meta属性返回指定值给回调函数—Scrapy内置图片下载器

    编写spiders爬虫文件循环抓取内容 Request()方法,将指定的url地址添加到下载器下载页面,两个必须参数, 参数: url='url' callback=页面处理函数 使用时需要yield ...

  8. 在写一个iOS应用之前必须做的7件事(附相关资源)

    本文由CocoaChina--不再犹豫(tao200610704@126.com)翻译 作者:@NIkant Vohra 原文:7 Things you must absolutely do befo ...

  9. 【MySQL】日期与字符串间的相互转换

    字符串转日期 下面将讲述如何在MySQL中把一个字符串转换成日期: 背景:rq字段信息为:20100901 无需转换的: SELECT * FROM tairlist_day WHERE rq> ...

  10. html表格导出Excel的一点经验心得(转载)

    最近在做统计功能,要求统计结果(表格)既能查看(BS系统,在浏览器查看),又能输出为excel文件.对于输出excel文件,在网上找到n种方案,因为还需查看,最终选择了统计结果输出为table,查看时 ...