【LG1600】[NOIP2016]天天爱跑步
【LG1600】[NOIP2016]天天爱跑步
题面
题解
考虑一条路径\(S\rightarrow T\)是如何给一个观测点\(x\)造成贡献的,
一种是从\(x\)的子树内出来,另外一种是从\(x\)的子树外进去。
令\(S,T\)的最近公共祖先为\(lca\),那么这条路径可表示为\(S\rightarrow lca\rightarrow T\)(如果\(lca=S\;or\;T\)可以特判)。
考虑两种情况如何贡献,
首先在\(S\rightarrow lca\)上的点,需要满足\(dep_S-dep_x=w_x\),
而对于\(lca\rightarrow T\)上的点,需要满足\((dep_S-dep_{lca})+(dep_x-dep_{lca})=w_x\Leftrightarrow dep_S-2dep_{lca}=w_x-dep_x\)。
这样的话,对于一条路径,我们可以拆成两条分别对其进行差分,在用一颗线段树在其对应位置上\(\pm 1\),然后线段树合并在对应位置上查即可。
具体实现细节详见代码。
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
inline int gi() {
    register int data = 0, w = 1;
    register char ch = 0;
    while (!isdigit(ch) && ch != '-') ch = getchar();
    if (ch == '-') w = -1, ch = getchar();
    while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar();
    return w * data;
}
const int MAX_N = 3e5 + 5;
struct Graph { int to, next; } e[MAX_N << 1];
int fir[MAX_N], e_cnt;
void clearGraph() { memset(fir, -1, sizeof(fir)); e_cnt = 0; }
void Add_Edge(int u, int v) { e[e_cnt] = (Graph){v, fir[u]}, fir[u] = e_cnt++; }
int fa[MAX_N], top[MAX_N], dep[MAX_N], size[MAX_N], son[MAX_N];
void dfs1(int x) {
	size[x] = 1, dep[x] = dep[fa[x]] + 1;
	for (int i = fir[x]; ~i; i = e[i].next) {
		int v = e[i].to; if (v == fa[x]) continue;
		fa[v] = x, dfs1(v), size[x] += size[v];
		if (size[son[x]] < size[v]) son[x] = v;
	}
}
void dfs2(int x, int tp) {
	top[x] = tp;
	if (son[x]) dfs2(son[x], tp);
	for (int i = fir[x]; ~i; i = e[i].next) {
		int v = e[i].to; if (v == son[x] || v == fa[x]) continue;
		dfs2(v, v);
	}
}
int LCA(int x, int y) {
	while (top[x] != top[y]) {
		if (dep[top[x]] < dep[top[y]]) swap(x, y);
		x = fa[top[x]];
	}
	return dep[x] < dep[y] ? x : y;
}
struct Path { int s, t, lca; } p[MAX_N];
int N, M, w[MAX_N], ans[MAX_N];
vector<int> Add1[MAX_N], Del1[MAX_N], Add2[MAX_N], Del2[MAX_N];
struct Node { int ls, rs, v; } t[MAX_N << 6];
int rt1[MAX_N], rt2[MAX_N], tot;
void insert(int &o, int l, int r, int pos, int op) {
	if (!o) o = ++tot;
	t[o].v += op;
	if (l == r) return ;
	int mid = (l + r) >> 1;
	if (pos <= mid) insert(t[o].ls, l, mid, pos, op);
	else insert(t[o].rs, mid + 1, r, pos, op);
}
int merge(int x, int y, int l, int r) {
	if (!x || !y) return x | y;
	if (l == r) return t[x].v += t[y].v, x;
	int mid = (l + r) >> 1;
	t[x].ls = merge(t[x].ls, t[y].ls, l, mid);
	t[x].rs = merge(t[x].rs, t[y].rs, mid + 1, r);
	return t[x].v = t[t[x].ls].v + t[t[x].rs].v, x;
}
int query(int o, int l, int r, int pos) {
	if (!o) return 0;
	if (l == r) return t[o].v;
	int mid = (l + r) >> 1;
	if (pos <= mid) return query(t[o].ls, l, mid, pos);
	else return query(t[o].rs, mid + 1, r, pos);
}
void Dfs(int x) {
	for (int i = fir[x]; ~i; i = e[i].next) {
		int v = e[i].to; if (v == fa[x]) continue;
		Dfs(v);
		rt1[x] = merge(rt1[x], rt1[v], -N, N << 1);
		rt2[x] = merge(rt2[x], rt2[v], -N, N << 1);
	}
	for (int i : Add1[x]) insert(rt1[x], -N, N << 1, i, 1);
	for (int i : Add2[x]) insert(rt2[x], -N, N << 1, i, 1);
	for (int i : Del1[x]) insert(rt1[x], -N, N << 1, i, -1);
	for (int i : Del2[x]) insert(rt2[x], -N, N << 1, i, -1);
	ans[x] = query(rt1[x], -N, N << 1, w[x] + dep[x]) + query(rt2[x], -N, N << 1, w[x] - dep[x]);
}
int main () {
#ifndef ONLINE_JUDGE
    freopen("cpp.in", "r", stdin);
#endif
	clearGraph();
	N = gi(), M = gi();
	for (int i = 1; i < N; i++) {
		int u = gi(), v = gi();
		Add_Edge(u, v), Add_Edge(v, u);
	}
	dfs1(1), dfs2(1, 1);
	for (int i = 1; i <= N; i++) w[i] = gi();
	for (int i = 1; i <= M; i++) {
		int s = gi(), t = gi(), lca = LCA(s, t);
		int d1 = dep[s], d2 = -dep[s];
		if (lca == t) { Add1[s].push_back(d1), Del1[fa[lca]].push_back(d1); continue; }
		if (lca == s) { Add2[t].push_back(d2), Del2[fa[lca]].push_back(d2); continue; }
		d2 = dep[s] - 2 * dep[lca];
		Add1[s].push_back(d1), Del1[fa[lca]].push_back(d1);
		Add2[t].push_back(d2), Del2[lca].push_back(d2);
	}
	Dfs(1);
	for (int i = 1; i <= N; i++) printf("%d ", ans[i]);
	putchar('\n');
    return 0;
}
												
											【LG1600】[NOIP2016]天天爱跑步的更多相关文章
- [NOIp2016]天天爱跑步 线段树合并
		
[NOIp2016]天天爱跑步 LG传送门 作为一道被毒瘤出题人们玩坏了的NOIp经典题,我们先不看毒瘤的"动态爱跑步"和"天天爱仙人掌",回归一下本来的味道. ...
 - [Noip2016]天天爱跑步 LCA+DFS
		
[Noip2016]天天爱跑步 Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要玩家每天按时上线,完成打卡任 ...
 - NOIP2016天天爱跑步 题解报告【lca+树上统计(桶)】
		
题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nn个 ...
 - BZOJ4719 [Noip2016]天天爱跑步
		
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...
 - noip2016天天爱跑步
		
题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 个结点 ...
 - bzoj 4719: [Noip2016]天天爱跑步
		
Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务.这个游戏的地图可以看作一一 ...
 - NOIP2016 天天爱跑步 80分暴力
		
https://www.luogu.org/problem/show?pid=1600 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养 ...
 - 4719: [Noip2016]天天爱跑步
		
Time Limit: 40 Sec Memory Limit: 512 MB Submit: 1986 Solved: 752 [Submit][Status][Discuss] Descripti ...
 - NOIP2016 天天爱跑步  线段树合并_桶_思维题
		
竟然独自想出来了,好开心 Code: #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r&q ...
 
随机推荐
- Redis的Sorted-Sets排行榜功能实现
			
Redis的ZSet排行榜功能实现 1. 功能需求 类似给用户n张图片, 用户左滑不喜欢右滑喜欢.所以每个用户就会有一些喜欢的图片集合和不喜欢的图片集合.现在我们要做一个将按照一个算法将喜欢的排到前面 ...
 - Redis集群模式介绍
			
前言: 一.为什么要使用redis 1,解决应用服务器的cpu和内存压力 2,减少io的读操作,减轻io的压力(内存中读取) 3,关系型数据库扩展性,不强,难以改变表的结构 二.优点 1,nosql数 ...
 - 大话设计模式Python实现-建造者模式
			
建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 下面是一个建造者模式的demo #!/usr/bin/env python # ...
 - 百度APP移动端网络深度优化实践分享(三):移动端弱网优化篇
			
本文由百度技术团队“蔡锐”原创发表于“百度App技术”公众号,原题为<百度App网络深度优化系列<三>弱网优化>,感谢原作者的无私分享. 一.前言 网络优化解决的核心问题有三个 ...
 - java 金额数字转换大写算法
			
根据人民币大写金额规范,转换有几点要注意的: 阿拉伯数字中间有"0"时,中文大写金额中间可以只写一个"零"字.如¥1,409.50,应写成人民币壹仟肆佰零玖圆伍 ...
 - .NET Core 多框架支持(net45+netstandard20)实践中遇到的一些问题总结
			
.NET Core 多框架支持(net45+netstandard20)实践中遇到的一些问题总结 前言 本文主要是关于.NET Standard 代码 在多框架 和 多平台 支持自己实践过程中遇到的一 ...
 - Winform中设置ZedGraph因设置小刻度导致的竖直虚线显示过多
			
场景 Winforn中设置ZedGraph曲线图的属性.坐标轴属性.刻度属性: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/10 ...
 - windows 下安装MongoDB
			
一:下载mongodb安装包 下载地址:https://www.mongodb.com/download-center/community 这里推荐下载msi的安装包 二:安装mongodb 双击下载 ...
 - linux应用管理
			
desktop文件的几个位置: /usr/share/applications ~/.local/share/applications /usr/local/share/applications li ...
 - 构建maven项目,自定义目录结构方法
			
构建maven项目 创建自定义的文件目录方法: 在项目名称右键-->Builder Path-->Configure Builder Path...Source菜单下的Add Folder ...