[WC 2014]紫荆花之恋
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]紫荆花之恋的更多相关文章
- 数据结构(平衡树,树分治,暴力重构):WC 2014 紫荆花之恋
[题目描述] 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来. 仔细看看的话,这棵大树实际上是一个带权 ...
- bzoj 3435: [Wc2014]紫荆花之恋 替罪羊树维护点分治 && AC400
3435: [Wc2014]紫荆花之恋 Time Limit: 240 Sec Memory Limit: 512 MBSubmit: 159 Solved: 40[Submit][Status] ...
- 【BZOJ3435】[Wc2014]紫荆花之恋 替罪点分树+SBT
[BZOJ3435][Wc2014]紫荆花之恋 Description 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从 ...
- BZOJ 3435: [Wc2014]紫荆花之恋
二次联通门 : BZOJ 3435: [Wc2014]紫荆花之恋 二次联通门 : luogu P3920 [WC2014]紫荆花之恋 /* luogu P3920 [WC2014]紫荆花之恋 怀疑人生 ...
- luogu P3920 [WC2014]紫荆花之恋
LINK:紫荆花之恋 每次动态加入一个节点 统计 有多少个节点和当前节点的距离小于他们的权值和. 显然我们不能n^2暴力. 考虑一个简化版的问题 树已经给出 每次求某个节点和其他节点的贡献. 不难想到 ...
- 【WC2014】紫荆花之恋(替罪羊重构点分树 & 平衡树)
Description 若带点权.边权的树上一对 \((u, v)\) 为 friend,那么需要满足 \(\text{dist}(u, v) \le r_u + r_v\),其中 \(r_x\) 为 ...
- BZOJ3435[Wc2014]紫荆花之恋——动态点分治(替罪羊式点分树套替罪羊树)
题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来.仔细看看的话,这个大树实际上是一个带权树.每 ...
- [WC2014]紫荆花之恋(动态点分治+替罪羊思想)
题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来.仔细看看的话,这个大树实际上是一个带权树.每 ...
- UOJ#55 [WC2014]紫荆花之恋
题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来. 仔细看看的话,这个大树实际上是一个带权树. ...
随机推荐
- js如何获取隐藏的元素的高度
首先,正常情况下,确保div是有高度的. <!DOCTYPE html> <html lang="en"> <head> <meta ch ...
- 敏捷冲刺每日报告五(Java-Team)
第五天报告(10.29 周日) 团队:Java-Team 成员: 章辉宇(284) 吴政楠(286) 陈阳(PM:288) 韩华颂(142) 胡志权(143) github地址:https://gi ...
- 20162328蔡文琛week07
学号 2016-2017-2 <程序设计与数据结构>第X周学习总结 教材学习内容总结 多态引用在不同的时候可以指向不同类型的对象. 多态引用在运行时才将方法调用用于它的定义绑定在一起. 引 ...
- 学号:201621123032 《Java程序设计》第2周学习总结
1: 本周学习总结 本周学习java的数据类型,两种数据类型:基本数据类型和引用数据类型. 学习关于String和StringBuilder之间不同. 本周还学习数组.一维数组,多维数组,和动态数组. ...
- python array 使用创建10万浮点数
from array import array from random floats = array('d',random((for i in range(10**7)) fp = open('flo ...
- TCP/IP协议复习
- iOS开发-OC分支结构
BOOL类型 返回值:真:YES 假:NO BOOL数据类型占一个字节的内存空间,占位符为%d. 计算机在识别时,YES就替换成1,NO就替换成0. bool是C语言中的布尔类型,返回值为true ...
- eclipse下maven一些配置方法汇总
随着eclipse的不同版本的变更:对maven插件的安装也有着不同的差异:之前也在一些版本的eclipse上安装成功地,但是最近又遇到了一些麻烦,故将这些方法记录下来: 大家都知道的最常用的一种方式 ...
- wireshark抓包分析tcp连接与断开
其实对于网络通信的学习,最好还是能够自己抓到包详细地一下,不然只单单通过文字和图的描述印象不够深刻.本文通过实际的抓包操作来看一下tcp的连接与断开是怎样的. 首先需要去https://www.wir ...
- Mongodb 3 查询优化(语句优化、建索引)
一.explain(),语句分析工具 MongoDB 3.0之后,explain的返回与使用方法与之前版本有了很大的变化,介于3.0之后的优秀特色和我们目前所使用给的是3.0.7版本,本文仅针对Mon ...