[NOIp2016]天天爱跑步

LG传送门

对于一个人,他的路程会分为两段,一段向上(根),一段向下,考虑在向上过程中他能产生贡献的观察者具有什么性质:设出发点深度为\(dep[x]\),观察者深度为\(dep[y]\),观察的时间为\(t\),需满足\(dep[x] - dep[y] = t\),换句话说就是\(dep[y] + t = dep[x]\)。向下那一段的推导类似,下面的部分也只以向上的路径为例来解释。

现在我们记录每个点下方出发点深度为\(dep[x]\)的人数,需要对于每个出发点更新出发点到出发点与目的地的lca的所有点,想到到开一颗权值线段树,用线段树合并不断把信息往上传,在lca处消除这次更新的影响,这样一来直接我们就可以在树上统计答案了。向下路径的处理与向上路径类似,这里就不再赘述,上代码。

#include <cstdio>
#include <cctype>
#include <vector>
#define R register
#define I inline
#define B 1000000
using namespace std;
const int N = 300001, M = 15000007;
char buf[B], *p1, *p2;
I char gc() { return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, B, stdin), p1 == p2) ? EOF : *p1++; }
I int rd() {
R int f = 0;
R char c = gc();
while (c < 48 || c > 57)
c = gc();
while (c > 47 && c < 58)
f = f * 10 + (c ^ 48), c = gc();
return f;
}
int w[N], s[N], t[N], p[N], q[N], d[N], r[N], u[N], v[N], o[N], n, C, S;
struct T{int f, p, q;}e[M];
vector <int> g[N];
I void swp(int &x, int &y) { x ^= y, y ^= x, x ^= y; }
void dfs1(int x, int f) {
p[x] = f, d[x] = d[f] + 1, t[x] = 1;
for (R int i = 0, y, m = 0; i < s[x]; ++i)
if ((y = g[x][i]) ^ f) {
dfs1(y, x), t[x] += t[y];
if (t[y] > m)
m = t[y], q[x] = y;
}
}
void dfs2(int x, int t) {
r[x] = t;
if (q[x])
dfs2(q[x], t);
for (R int i = 0, y; i < s[x]; ++i)
if ((y = g[x][i]) ^ p[x] && y ^ q[x])
dfs2(y, y);
}
I int lca(int x, int y) {
while (r[x] ^ r[y]) {
if (d[r[x]] < d[r[y]])
swp(x, y);
x = p[r[x]];
}
if (d[x] > d[y])
swp(x, y);
return x;
}
void ins(int &k, int l, int r, int x, int v) {
if (!k)
k = ++C;
e[k].f += v;
if (l == r)
return ;
R int m = l + r >> 1;
if (x <= m)
ins(e[k].p, l, m, x, v);
else
ins(e[k].q, m + 1, r, x, v);
}
int mrg(int k, int t) {
if (!k)
return t;
if (!t)
return k;
e[k].f += e[t].f, e[k].p = mrg(e[k].p, e[t].p), e[k].q = mrg(e[k].q, e[t].q);
return k;
}
int qry(int k, int l, int r, int x) {
if (l == r)
return e[k].f;
R int m = l + r >> 1;
if (x <= m)
return qry(e[k].p, l, m, x);
else
return qry(e[k].q, m + 1, r, x);
}
void dfs(int x) {
for (R int i = 0, y; i < s[x]; ++i)
if ((y = g[x][i]) ^ p[x])
dfs(y), u[x] = mrg(u[x], u[y]), v[x] = mrg(v[x], v[y]);
o[x] = qry(u[x], 1, S, w[x] + d[x]) + qry(v[x], 1, S, w[x] - d[x] + n);
}
int main() {
R int m, i, x, y, a;
n = rd(), m = rd(), S = n << 1;
for (i = 1; i < n; ++i)
x = rd(), y = rd(), g[x].push_back(y), g[y].push_back(x);
for (i = 1; i <= n; ++i)
s[i] = g[i].size(), w[i] = rd();
dfs1(1, 0), dfs2(1, 1);
for (i = 1; i <= m; ++i)
x = rd(), y = rd(), a = lca(x, y), ins(u[x], 1, S, d[x], 1), ins(u[a], 1, S, d[x], -1), ins(v[y], 1, S, d[x] - (d[a] << 1) + n, 1), ins(v[p[a]], 1, S, d[x] - (d[a] << 1) + n, -1);
dfs(1);
for (i = 1; i <= n; ++i)
printf("%d ", o[i]);
return 0;
}

因为减的结果可能有负数,所以加上一个\(n\),值域变两倍。

[NOIp2016]天天爱跑步 线段树合并的更多相关文章

  1. NOIP2016 天天爱跑步 线段树合并_桶_思维题

    竟然独自想出来了,好开心 Code: #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r&q ...

  2. 2018.08.09 bzoj4719: [Noip2016]天天爱跑步(树链剖分)

    传送门 话说开始上文化课之后写题时间好少啊. 这道题将一个人的跑步路线拆成s->lca,lca->t,然后对于第一段上坡路径要经过的点,当前这个人能对它产生贡献当且仅当dep[s]-dep ...

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

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

  4. [NOIP2016 DAY1 T2]天天爱跑步-[差分+线段树合并][解题报告]

    [NOIP2016 DAY1 T2]天天爱跑步 题面: B[NOIP2016 DAY1]天天爱跑步 时间限制 : - MS 空间限制 : 565536 KB 评测说明 : 2s Description ...

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

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

  6. BZOJ4719 NOIP2016天天爱跑步(线段树合并)

    线段树合并的话这个noip最难题就是个裸题了. 注意merge最后return x,以及如果需要区间查询的话这里还需要up,无数次死于这里. #include<iostream> #inc ...

  7. 【bzoj4719】[Noip2016]天天爱跑步 权值线段树合并

    题目描述 给出一棵n个点的树,以及m次操作,每次操作从起点向终点以每秒一条边的速度移动(初始时刻为0),最后对于每个点询问有多少次操作在经过该点的时刻为某值. 输入 第一行有两个整数N和M .其中N代 ...

  8. 洛谷P1600 天天爱跑步(线段树合并)

    小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nn ...

  9. 【LG1600】[NOIP2016]天天爱跑步

    [LG1600][NOIP2016]天天爱跑步 题面 洛谷 题解 考虑一条路径\(S\rightarrow T\)是如何给一个观测点\(x\)造成贡献的, 一种是从\(x\)的子树内出来,另外一种是从 ...

随机推荐

  1. python 基础-----数字,字符串,if while 循环 数据类型的转换简单介绍

    一.第一个python小程序 首先我们要知道python创立的初衷是:Python崇尚优美.清晰.简单. 所以python比起其他的语言需要的工作量少了一半都不止,比如和现在一直霸占语言排行榜  榜首 ...

  2. ARC下的block导致的循环引用问题解析

    ARC下的block导致的循环引用问题解析 更详细细节请参考 http://blog.sina.com.cn/s/blog_8c87ba3b0101m599.html ARC下,copy到堆上的blo ...

  3. UIView的无损截图

    UIView的无损截图 说明 1. 烂大街的代码 2. 写成category后,方便直接从drawRect中获取绘制出来的图片 3. 可以直接绘制图片供按钮设置背景图片用 4. 无损截图(包括alph ...

  4. Linux架构之简述企业网站简述

    简述企业网站 用户  --> 负载均衡服务器(Nginx)  ->根据扩展名访问不同的服务区 ->访问数据库 ->返回用户          静态服务器&&动态 ...

  5. 重置 Winsock:初始化计算机网络环境

    初始化网络环境,以解决由于软件冲突.病毒原因造成的参数错误问题(复杂网络环境下慎用).批处理代码: netsh winhttp reset proxy netsh winhttp reset trac ...

  6. 一、DAO设计模式 二、DAO设计模式的优化 三、JDBC中的事务,连接池的使用

    一.DAO设计模式概述###<1>概念 DAO,Data Access Object ,用于访问数据库的对象. 位于业务逻辑和数据持久化层之间,实现对数据持久化层的访问![](1.png) ...

  7. C++ 课堂作业1.0

    c++第一次课堂作业点这里 题目要求:输入半径,计算圆的面积,在调用外部函数,无需使用类.

  8. kudu安装部署

    安装部署节点规划 节点 kudu-master kudu-tserver node01 是 是 node02 是 是 node03 是 是 配置本地Yum的Repository 下载kudu安装yum ...

  9. BZOJ1189:[HNOI2007]紧急疏散EVACUATE(最大流,枚举)

    Description 发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域.每个格子如果是'.',那么表示这是一 块空地:如果是'X',那么表示这是一面墙,如果是'D',那么表示这是 ...

  10. 【bzoj 4066】 简单题

    题目 显然这就是让我们在二维上数个点 如果没有强制在线就随便做啦,扫描线+主席树应该是最好的选择 但是现在强制在线并且卡了树套树的空间,于是只能上\(kdt\)了 我们还是维护一下每个子树分割出来的矩 ...