Description

强强和萌萌是一对好朋友。有一天他们在外面闲逛,突然看到前方有一棵紫荆树。这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来。

仔细看看的话,这个大树实际上是一个带权树。每个时刻它会长出一个新的叶子节点,每个节点上有一个可爱的小精灵,新长出的节点上也会同时出现一个新的小精灵。小精灵是很萌但是也很脆弱的生物,每个小精灵 $i$ 都有一个感受能力值 $r_i$,小精灵 $i, j$ 成为朋友当且仅当在树上 $i$ 和 $j$ 的距离 $\text{dist}(i, j) \leq r_i + r_j$,其中 $\text{dist}(i, j)$ 表示在这个树上从 $i$ 到 $j$ 的唯一路径上所有边的边权和。

强强和萌萌很好奇每次新长出一个叶子节点之后,这个树上总共有几对朋友。

我们假定这个树一开始为空,节点按照加入的顺序从 $1$ 开始编号。由于强强非常好奇,你必须在他每次出现新结点后马上给出总共的朋友对数,不能拖延哦。

Input

第一行包含一个整数,表示测试点编号。

第二行包含一个正整数 $n$,表示总共要加入的节点数。

我们令加入节点前的总共朋友对数是 $\text{last_ans}$,在一开始时它的值为 $0$。

接下来 $n$ 行中第 $i$ 行有三个非负整数 $a_i, c_i, r_i$,表示结点 $i$ 的父节点的编号为 $a_i xor (\text{last_ans} \bmod 10^9)$(其中 $xor$ 表示异或,$\bmod$表示取余,数据保证这样操作后得到的结果介于 $1$ 到 $i - 1$ 之间),与父结点之间的边权为 $c_i$,节点 $i$ 上小精灵的感受能力值为 $r_i$。

注意 $a_1 = c_1 = 0$,表示 $1$ 号节点是根结点,对于 $i > 1$,父节点的编号至少为 $1$。

Output

包含 $n$ 行,每行输出 $1$ 个整数,表示加入第 $i$ 个点之后,树上有几对朋友。

Sample Input

0
5
0 0 6
1 2 4
0 9 4
0 5 5
0 2 4

Sample Output

0
1
2
4
7

Hint

对于所有数据,满足 $1 \leq c_i \leq 10000$,$a_i \leq 2 \times 10^9$,$r_i \leq 10^9$。

测试点编号 约定
1, 2 $n \leq 100$
3, 4 $n \leq 1000$
5, 6, 7, 8 $n \leq 100000$,节点 $1$ 最多有两个子节点,其它节点最多有一个子节点
9, 10 $n \leq 100000$,$r_i \leq 10$
11, 12 $n \leq 100000$,这棵树是随机生成的
13, 14, 15 $n \leq 70000$
16, 17, 18, 19, 20 $n \leq 100000$

此题 hack 时忽略输入数据中给定的测试点编号对测试点的限制。

祝大家一遍 AC,求不虐萌萌哒测评机!

时间限制:$12\texttt{s}$

空间限制:$512\texttt{MB}$

题解

有生之年竟然能切这道题...尽管常数大得吓人...但在 $UOJ$ 上 A 的掉。

用动态点分治做过[ZJOI 2007]Hide 捉迷藏[ZJOI 2015]幻想乡战略游戏(或[HNOI 2015]开店)应该来说不是很难的...

做法还是自己 YY 的,不知道是否有更好的方法。

首先,对于题目要求 $dist(u, v) \leq r_u+r_v$ ,我们从 $u$ 在点分树向上跳的时候,第一次处理到含点 $v$ 的重心,那么这个重心就是 $lca(u, v)$ ,我们对这个 $lca$ 进行处理。

由于满足上式,所以 $dist(u, lca)+dist(v, lca) \leq r_u+r_v$ 等价于若点 $v$ 满足 $dist(v, lca)-r_v \leq r_u-dist(u, lca)$ 那么显然 $v$ 是满足与 $u$ 是好朋♂友的。

那么我们可以在每个节点上建一棵平衡树,维护以其为重心的子树中 $dist(v, lca)-r_v$ 的值,显然统计答案就是平衡树中 $\leq r_u-dist(u, lca)$ 的个数。

按照套路,为了防止重复计算,我们需要减去会在这个重心的父亲处重复计算的值。记在点分树中 $u$ 节点的父亲为 $fa_u$ ,所以我们再开一个平衡树来存 $dist(fa_{lca}, v)-r_v$ ,额外减去的就是第二棵平衡树中 $\leq r_u-dist(fa_{lca}, u)$ 的个数。

对于加点的操作,我们直接在原图上添加,用替罪羊的思想,若以 $u$ 为根的子树大小出现不平衡,直接将以 $u$ 为根的整棵子树拍平用点分治重建。

 //It is made by Awson on 2018.1.10
#include <set>
#include <map>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define lowbit(x) ((x)&(-(x)))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
using namespace std;
const int N = ;
const int MAXS = N*;
const double alpha = 0.88;
const int MOD = 1e9;
const int INF = ~0u>>;
void read(int &x) {
char ch; bool flag = ;
for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || ); ch = getchar());
for (x = ; isdigit(ch); x = (x<<)+(x<<)+ch-, ch = getchar());
x *= -*flag;
}
void write(LL x) {
if (x > ) write(x/);
putchar(x%+);
} int n, lim, a, c, r[N+], fa[N+], vis[N+], size[N+]; LL last_ans;
struct tt {
int to, next, cost;
}edge[(N<<)+];
int path[N+], top;
void add(int u, int v, int c) {
edge[++top].to = v, edge[top].cost = c, edge[top].next = path[u]; path[u] = top;
}
vector<int>to[N+];
struct Treap {
int root[N+], ch[MAXS+][], key[MAXS+], lev[MAXS+], size[MAXS+], pos;
queue<int>mem;
void newnode(int &o, int keyy) {
if (!mem.empty()) o = mem.front(), mem.pop();
else o = ++pos;
ch[o][] = ch[o][] = , lev[o] = rand(), key[o] = keyy, size[o] = ;
}
void pushup(int o) {size[o] = size[ch[o][]]+size[ch[o][]]+; }
void rotate(int &o, int kind) {
int x = ch[o][!kind];
ch[o][!kind] = ch[x][kind];
ch[x][kind] = o;
o = x;
}
void insert(int &o, int keyy) {
if (!o) {newnode(o, keyy); return; }
size[o]++;
int kind = keyy >= key[o];
insert(ch[o][kind], keyy);
if (lev[ch[o][kind]] < lev[o]) rotate(o, !kind), pushup(ch[o][!kind]), pushup(o);
}
int query(int o, int keyy) {
if (!o) return ;
if (keyy < key[o]) return query(ch[o][], keyy);
else return size[ch[o][]]++query(ch[o][], keyy);
}
void travel(int o) {
if (ch[o][]) travel(ch[o][]);
mem.push(o);
if (ch[o][]) travel(ch[o][]);
}
void recycle(int id) {
if (!root[id]) return;
travel(root[id]); root[id] = ;
}
}T1, T2;
namespace LCA {
int dep[N+], f[N+][], dis[N+];
void update(int fa, int o, int dist) {
f[o][] = fa, dep[o] = dep[fa]+, dis[o] = dis[fa]+dist;
for (int t = ; t <= lim; t++) f[o][t] = f[f[o][t-]][t-];
}
int query(int x, int y) {
if (dep[x] < dep[y]) Swap(x, y);
for (int i = lim; i >= ; i--) if (dep[f[x][i]] >= dep[y]) x = f[x][i];
if (x == y) return x;
for (int i = lim; i >= ; i--) if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
return f[x][];
}
int dist(int x, int y) {return dis[x]+dis[y]-(dis[query(x, y)]<<); }
}
namespace Point_divide {
int size[N+], mx[N+], root, minsize;
void get_size(int o, int fa) {
size[o] = , mx[o] = ;
for (int i = path[o]; i; i = edge[i].next)
if (edge[i].to != fa && !vis[edge[i].to]) {
get_size(edge[i].to, o);
size[o] += size[edge[i].to];
if (size[edge[i].to] > mx[o]) mx[o] = size[edge[i].to];
}
}
void get_root(int o, int pa, int fa) {
mx[o] = Max(mx[o], size[pa]-size[o]);
if (mx[o] < minsize) minsize = mx[root = o];
for (int i = path[o]; i; i = edge[i].next)
if (edge[i].to != fa && !vis[edge[i].to]) get_root(edge[i].to, pa, o);
}
void get_push(int o, int pa, int da, int fa, int cost) {
T1.insert(T1.root[da], cost-r[o]); if (pa) T2.insert(T2.root[da], LCA::dist(pa, o)-r[o]);
for (int i = path[o]; i; i = edge[i].next)
if (edge[i].to != fa && !vis[edge[i].to]) get_push(edge[i].to, pa, da, o, cost+edge[i].cost);
}
int work(int o, int pa) {
minsize = INF, get_size(o, ), get_root(o, o, ); vis[root] = , fa[root] = pa; if (pa) to[pa].push_back(root); int rt = root;
T1.insert(T1.root[root], -r[root]); if (pa) T2.insert(T2.root[root], LCA::dist(pa, root)-r[root]);
for (int i = path[root]; i; i = edge[i].next)
if (!vis[edge[i].to]) get_push(edge[i].to, pa, root, , edge[i].cost);
for (int i = path[root]; i; i = edge[i].next)
if (!vis[edge[i].to]) work(edge[i].to, rt);
return rt;
}
}
int balance(int o, int son) {return size[o]*alpha >= size[son]; } int update(int o) {
int w = ; size[o]++;
for (int x = o; x; x = fa[x]) {
if (fa[x]) size[fa[x]]++;
T1.insert(T1.root[x], LCA::dist(x, o)-r[o]);
if (fa[x]) T2.insert(T2.root[x], LCA::dist(fa[x], o)-r[o]);
if (fa[x] && !balance(fa[x], x)) w = fa[x];
}
return w;
}
void destroy(int o) {
vis[o] = ;
for (int i = , tol = to[o].size(); i < tol; i++) destroy(to[o][i]);
T1.recycle(o), T2.recycle(o); to[o].clear();
}
void pushup(int o) {
size[o] = ;
for (int i = , tol = to[o].size(); i < tol; i++) pushup(to[o][i]), size[o] += size[to[o][i]];
}
void rebuild(int o) {
int x = -, f = fa[o];
if (f) for (int i = , tol = to[fa[o]].size(); i < tol; i++) if (to[fa[o]][i] == o) {x = i; break; }
destroy(o);
int y = Point_divide::work(o, fa[o]);
if (f) {to[f].pop_back(); to[f][x] = y; }
pushup(y);
}
int query(int o) {
int ans = ;
for (int x = o; x; x = fa[x]) {
ans += T1.query(T1.root[x], r[o]-LCA::dist(o, x));
if (fa[x]) ans -= T2.query(T2.root[x], r[o]-LCA::dist(o, fa[x]));
}
return ans-;
}
void work() {
scanf("%d", &n), scanf("%d" ,&n); lim = log(n)/log();
for (int i = ; i <= n; i++) {
scanf("%d%d%d", &a, &c, &r[i]);
a = a^(last_ans%MOD);
if (a != ) add(a, i, c), add(i, a, c); fa[i] = a, to[a].push_back(i); vis[i] = ;
LCA::update(a, i, c); int x = update(i); if (x) rebuild(x);
last_ans += query(i); write(last_ans); putchar('\n');
}
}
int main() {
srand(time()); work();
return ;
}

[WC 2014]紫荆花之恋的更多相关文章

  1. 数据结构(平衡树,树分治,暴力重构):WC 2014 紫荆花之恋

    [题目描述] 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来. 仔细看看的话,这棵大树实际上是一个带权 ...

  2. bzoj 3435: [Wc2014]紫荆花之恋 替罪羊树维护点分治 && AC400

    3435: [Wc2014]紫荆花之恋 Time Limit: 240 Sec  Memory Limit: 512 MBSubmit: 159  Solved: 40[Submit][Status] ...

  3. 【BZOJ3435】[Wc2014]紫荆花之恋 替罪点分树+SBT

    [BZOJ3435][Wc2014]紫荆花之恋 Description 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从 ...

  4. BZOJ 3435: [Wc2014]紫荆花之恋

    二次联通门 : BZOJ 3435: [Wc2014]紫荆花之恋 二次联通门 : luogu P3920 [WC2014]紫荆花之恋 /* luogu P3920 [WC2014]紫荆花之恋 怀疑人生 ...

  5. luogu P3920 [WC2014]紫荆花之恋

    LINK:紫荆花之恋 每次动态加入一个节点 统计 有多少个节点和当前节点的距离小于他们的权值和. 显然我们不能n^2暴力. 考虑一个简化版的问题 树已经给出 每次求某个节点和其他节点的贡献. 不难想到 ...

  6. 【WC2014】紫荆花之恋(替罪羊重构点分树 & 平衡树)

    Description 若带点权.边权的树上一对 \((u, v)\) 为 friend,那么需要满足 \(\text{dist}(u, v) \le r_u + r_v\),其中 \(r_x\) 为 ...

  7. BZOJ3435[Wc2014]紫荆花之恋——动态点分治(替罪羊式点分树套替罪羊树)

    题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来.仔细看看的话,这个大树实际上是一个带权树.每 ...

  8. [WC2014]紫荆花之恋(动态点分治+替罪羊思想)

    题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来.仔细看看的话,这个大树实际上是一个带权树.每 ...

  9. UOJ#55 [WC2014]紫荆花之恋

    题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来. 仔细看看的话,这个大树实际上是一个带权树. ...

随机推荐

  1. c语言程序设计第4周编程练习(素数和)

    1 素数和(5分) 题目内容: 我们认为2是第一个素数,3是第二个素数,5是第三个素数,依次类推. 现在,给定两个整数n和m,0<n<=m<=200,你的程序要计算第n个素数到第m个 ...

  2. HIVE的常用操作(HQL)语句

    HIVE基本操作命令 创建数据库 >create database db_name; >create database if not exists db_name;//创建一个不存在的数据 ...

  3. 判断mine类型

    var http = require("http"); var fs = require("fs"); var url = require("url& ...

  4. 视图和URL配置

    视图和URL配置 实验简介 上一章里我们介绍了如何创建一个Django项目并启动Django的开发服务器.本章你将学到用Django创建动态网页的基本知识. 同时,也教会大家怎么在本地机器上建立一个独 ...

  5. Linux环境下发布.net core

    一.安装Linux环境 1. 安装VM虚拟机和操作系统 VM虚拟工具安装的过程详见:http://blog.csdn.net/stpeace/article/details/78598333.直接按照 ...

  6. 遍历JSON

    第一种: each,不做详细说明,太常用了 第二种:我用来遍历单个组,实现前端界面绑定 for(var item in person){ alert("person中"+item+ ...

  7. 深度学习之 cnn 进行 CIFAR10 分类

    深度学习之 cnn 进行 CIFAR10 分类 import torchvision as tv import torchvision.transforms as transforms from to ...

  8. 使用 dynamic 类型让 ASP.NET Core 实现 HATEOAS 结构的 RESTtful API

    上一篇写的是使用静态基类方法的实现步骤:  http://www.cnblogs.com/cgzl/p/8726805.html 使用dynamic (ExpandoObject)的好处就是可以动态组 ...

  9. 阿里云API网关(4)快速入门(开放 API)

    网关指南: https://help.aliyun.com/document_detail/29487.html?spm=5176.doc48835.6.550.23Oqbl 网关控制台: https ...

  10. HTML中的上下标标签的演示

    HTML中的上下标标签的演示 #table_head>td { font-weight: bold } tr { text-align: center } 作用 标签 演示代码 呈现效果 上标 ...