[luogu1600] 天天爱跑步
题面
 直接写正解吧, 不想再写部分分了, 对于\(u\)和\(v\), 我们可以将它拆成两条路径, \(u\)到\(lca(u, v)\)和\(lca(u, v)\)到v, 在这里只分析从\(u\)到\(lca(u, v)\)的路径(其实是我不想写).
 对于一个点\(u\), 设它的深度为\(dep[u]\), 值为\(dep[i] + w[i]\)的物品有\(cnt[w[i] + dep[i]]\)个, 这样的话, 只有在满足\(dep[u] - dep[i] = w[i]\)的时候, 才能对这个点产生贡献, 由于这三个数都是确定的, 所以在某个起点出发到一个终点结束的路径, 我们处理出他的lca后, 可以使用树上差分, 将一个值为\(dep[u]\)的物品从\(u\)传入, 从\(lca(u, v)\)的父亲传出, 这样就可以对每个点进行树上差分, 在插入之前记录一下\(cnt[w[i] + dep[i]]\)的物品有多少个, 再从底往上更新, 查询当前点\(dep[i] + w[i]\)的物品有多少个, 相减即可.
 至于\(lca(u, v)\)的情况, 大家根据上面列一个式子用同样的方法判断就行了, 这里只列出式子, 大家也可以自己推导一下, 最后是这个样子\(dep[u] + dep[i] - 2 * dep[lca(u, v)] = w[i]\), 有可能等式左边的会小于零, 在数组上平移一段即可.
具体代码
#include <iostream>
#include <cstdio>
#include <vector>
#define N 300005
using namespace std;
int n, m, w[N], head[N], cnt, f[N][20], dep[N], num[N], c1[N], c2[N << 1];
struct node
{
	int to, next;
} edge[N << 1];
vector<int> lin[N], lout[N], rin[N], rout[N]; 
inline int read()
{
	int x = 0, w = 1;
	char c = getchar();
	while(c < '0' || c > '9') { if (c == '-') w = -1; c = getchar(); }
	while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
	return x * w;
}
inline void add(int u, int v) { edge[++cnt].to = v; edge[cnt].next = head[u]; head[u] = cnt; }
void dfs(int u, int fa)
{
	dep[u] = dep[fa] + 1;
	for(int i = 1; i <= 18 && f[f[u][i - 1]][i - 1]; i++)
		f[u][i] = f[f[u][i - 1]][i - 1];
	for(int i = head[u]; i; i = edge[i].next)
	{
		int v = edge[i].to; if(v == fa) continue;
		f[v][0] = u; dfs(v, u);
	}
}
int LCA(int u, int v)
{
	if(dep[u] > dep[v]) swap(u, v);
	for(int i = 18; i >= 0; i--)
		if(dep[f[v][i]] >= dep[u]) v = f[v][i];
	if(v == u) return u;
	for(int i = 18; i >= 0; i--)
		if(f[u][i] != f[v][i]) { u = f[u][i]; v = f[v][i]; }
	return f[u][0];
}
void down(int u)
{
	int sum1 = c1[w[u] + dep[u]], sum2 = c2[w[u] - dep[u] + 300000];
	for(int i = head[u]; i; i = edge[i].next)
		if(edge[i].to != f[u][0]) down(edge[i].to);
	for(unsigned int i = 0; i < lin[u].size(); i++) c1[lin[u][i]]++;//记录一下
	for(unsigned int i = 0; i < lout[u].size(); i++) c1[lout[u][i]]--;
	for(unsigned int i = 0; i < rin[u].size(); i++) c2[rin[u][i] + 300000]++;
	for(unsigned int i = 0; i < rout[u].size(); i++) c2[rout[u][i] + 300000]--;//记得平移
	num[u] += c1[w[u] + dep[u]] - sum1 + c2[w[u] - dep[u] + 300000] - sum2; //相减即为答案
}
int main()
{
	n = read(); m = read();
	for(int i = 1; i < n; i++)
	{
		int u = read(), v = read();
		add(u, v); add(v, u);
	}
	for(int i = 1; i <= n; i++) w[i] = read();
	dfs(1, 0);
	for(int i = 1; i <= m; i++)
	{
		int u = read(), v = read();
		int lca = LCA(u, v);
		lin[u].push_back(dep[u]); lout[f[lca][0]].push_back(dep[u]); rin[v].push_back(dep[u] - 2 * dep[lca]); rout[lca].push_back(dep[u] - 2 * dep[lca]); //u到lca和lca到v, 由于lca已经走过, 这个时候从lca传入就相当于这个物品是在lca与v那条链上lca的儿子传入, 差分嘛
	}
	down(1);
	for(int i = 1; i <= n; i++) printf("%d%c", num[i], i == n ? '\n' : ' ');
	return 0;
}
完
[luogu1600] 天天爱跑步的更多相关文章
- [luogu1600 noip2016] 天天爱跑步 (树上差分)
		
题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵 ...
 - UOJ261 【NOIP2016】天天爱跑步
		
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...
 - BZOJ4719 [Noip2016]天天爱跑步
		
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...
 - noip2016天天爱跑步
		
题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 个结点 ...
 - bzoj 4719: [Noip2016]天天爱跑步
		
Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务.这个游戏的地图可以看作一一 ...
 - [NOIP]2016天天爱跑步
		
[NOIP]2016天天爱跑步 标签: LCA 树上差分 NOIP Description 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是 ...
 - NOIP2016 天天爱跑步 80分暴力
		
https://www.luogu.org/problem/show?pid=1600 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养 ...
 - [NOIp 2016]天天爱跑步
		
Description 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图 ...
 - 【NOIP2016】【LCA】【树上差分】【史诗级难度】天天爱跑步
		
学弟不是说要出丧题吗>>所以我就研究了1天lca又研究了1天tj然后研究了一天天天爱跑步,终于写了出来.(最后的平均用时为240ms...比学弟快了1倍...) 题意:给你颗树,然后有m个 ...
 
随机推荐
- oracle数据库定时任务
			
应用系统运行中,经常需要定时执行一些任务,例如:定时更新汇总数据,定时更新状态数据等,目前 Treesoft数据库管理系统 增加[定时任务]功能,直接通过页面简单配置,即可按调度规则定时执行SQL任务 ...
 - 数组原型方法调用及函数apply调用时 类数组参数在IE8下的问题
			
当函数以 apply 方式调用时, 传参方式是一个由各个参数组成的数组或类数组(一个有length属性的对象),传入参数个数取决于 length 的值,例如,某个对象 args.length=3; a ...
 - nodejs做的一个测试端口程序
			
最近在学习nodejs的http,然后做了一个测试域名有没有使用那些端口,原意是用来做一个本地的静态服务器,然后运行前先测试端口,首先要用到的是net模块,主要用到的是Socket,判断其连接状态即可 ...
 - mootools vs jquery
			
大部分最近才剛接觸JavaScript的人會面臨到的困難是該選擇哪個套件(library)或是該先學哪個套件.如果你在一間公司裡上班,那麼可能公司已經有一套固定使用的套件,若是在這種情況下,問題就沒那 ...
 - 【代码笔记】iOS-自动成表格的效果
			
一,效果图. 二,工程图. 三,代码. RootViewController.h #import <UIKit/UIKit.h> #import "LabelOnBackImag ...
 - display none隐藏后如果表单有数值,那么他的数值还存在!
			
以前以为display:none后他的值就不存在了, display:none隐藏后如果表单有数值,那么他的数值还存在.(项目出了问题!!) <!DOCTYPE html PUBLIC &quo ...
 - IT小鲜肉 widgets tree 三种格式数据源
			
昨天完成了下面几个功能,其中最麻烦的就是做图.边学GIMP用法边做图 1.使用GIMP软件G了几个图标 2.支持一维数组数据源,并按照指定的属性对数据源中的数据进行自动分组 运行效果: 3.支持由pi ...
 - ComboBox Style
			
<SolidColorBrush x:Key="ComboBoxNormalBorderBrush" Color="#e3e9ef" /> < ...
 - Android 自定义AlertDialog(退出提示框)
			
有时候我们需要在游戏或应用中用一些符合我们样式的提示框(AlertDialog) 以下是我在开发一个小游戏中总结出来的.希望对大家有用. 先上效果图: 下面是用到的背景图或按钮的图片 经过查找资料和参 ...
 - java变量常量
			
1. java 变量遵循先声明,再赋值,后使用的原则. 一个变量可以只声明,不赋值,没有问题(只是这个变量没有实际意义,但完全没有问题).但如果想要使用它,那么就一定要给它赋值,而大多数时候我们又不知 ...