【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 ...
随机推荐
- 解决静态方法调用注入的service
在使用jpa的复杂查询时,声明了specification时声明为静态方法,导致注入的service无法使用,故想到俩种方式,一种手动注入,一种注解注入,此文使用的时注解注入: 解决静态方法调用注入的 ...
- LeetCode20——有效的括号
在记事本中写算法题和在纸上写其实感觉差不多,反正是不能进行调试.想起某高手的话,写代码要做到“人机合一”,写高级语言时(指的是 C 和 C++)脑海中要知道当前写的代码对应的反汇编代码,也就是要深入了 ...
- vuex源码分析(二) state及strict属性 详解
state也就是vuex里的值,也即是整个vuex的状态,而strict和state的设置有关,如果设置strict为true,那么不能直接修改state里的值,只能通过mutation来设置 例1: ...
- POJ-1129 DFS染色+四色原理的应用
OJ-ID: POJ-1129 author: Caution_X date of submission: 20190927 tags: DFS+四色原理的应用 descri ...
- Microsoft.Extensions.DependencyInjection 之二:使用诊断工具观察内存占用
目录 准备工作 大量接口与实现类的生成 elasticsearch+kibana+apm asp.net core 应用 请求与快照 Kibana 上的请求记录 请求耗时的分析 请求内存的分析 第2次 ...
- mvc5 源码解析1:UrlRoutingModule
注册在C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG \webconfig中 在该module源码中 我们可以看出注册了application ...
- Python requests库的使用(二)
1.请求异常处理 请求异常类型: 请求超时处理(timeout): 实现代码: import requestsfrom requests import exceptions #引入exc ...
- scrapy框架抓取表情包/(python爬虫学习)
抓取网址:https://www.doutula.com/photo/list/?page=1 1.创建爬虫项目:scrapy startproject biaoqingbaoSpider 2.创建爬 ...
- JVM指令手册
JVM指令大全 常量入栈指令 指令码 操作码(助记符) 操作数 描述(栈指操作数栈) 0x01 aconst_null null值入栈. 0x02 iconst_m1 -1(int)值入栈. 0x03 ...
- MQ 分布式事务 -- 微服务应用
1.背景 友情链接:https://www.cnblogs.com/Agui520/p/11187972.html https://blog.csdn.net/fd2025/article/detai ...