[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]紫荆花之恋
题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来. 仔细看看的话,这个大树实际上是一个带权树. ...
随机推荐
- VC++开发AutoCAD 2018/objectARX 用向导新建项目无法新建的问题
话说笔者最近想用新机子上装的AutoCAD ObjectARX 2018来进行二次开发,兴致勃勃安装了ARX API和向导, 然后打开VS2015,新建项目,无法新建. 折腾了一下,还是没有解决,后面 ...
- Alpha冲刺Day7
Alpha冲刺Day7 一:站立式会议 今日安排: 由林静和周静平共同完成企业风险分级展示这一模块的分级列表展示,该模块主要提供企业自查风险的条件查询功能 由黄腾飞和张梨贤共同完成企业风险分级展示的分 ...
- github上传时出现error: src refspec master does not match any解决办法
github上传时出现error: src refspec master does not match any解决办法 这个问题,我之前也遇到过,这次又遇到了只是时间间隔比较长了,为了防止以后再遇到类 ...
- HTTP协议以及HTTP2.0/1.1/1.0区别
HTTP协议以及HTTP2.0/1.1/1.0区别 一.简介 摘自百度百科: 超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议.所 ...
- Hibernate与mysql的对应类型
Hibernate映射类型 Java类型 标准SQL类型 integer java.lang.Integer integer long java.lang.Long bigint sho ...
- monog和github学习
1.导出服务器数据库到本地以json的格式储存:mongoexport -h ip -d dbname -c user -o D:\mondb\user.json2.导入本地Json到本地项目中:D: ...
- LeetCode & Q14-Longest Common Prefix-Easy
String Description: Write a function to find the longest common prefix string amongst an array of st ...
- c 语言常量
1,整数常量 整数常量可以是十进制.八进制或十六进制的常量.前缀指定基数:0x 或 0X 表示十六进制,0 表示八进制,不带前缀则默认表示十进制. 整数常量也可以带一个后缀,后缀是 U 和 L 的组合 ...
- ELK学习总结(2-1)mavel -》sense 和 索引初始化
1.安装 sudo elasticsearch/bin/plugin -install elasticsearch/mavel/latest http://localhost:9200/_plugi ...
- 模板引擎Jade详解
有用的符号: | 竖杠后的字符会被原样输出 · 点表示下一级的所有字符都会被原样输出,不再被识别.(就是|的升级版,实现批量) include 表示引用外部文件 短杠说明后面跟着的字符只是一段代码(与 ...