题目描述

强强和萌萌是一对好朋友。有一天他们在外面闲逛,突然看到前方有一棵紫荆树。这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来。仔细看看的话,这个大树实际上是一个带权树。每个时刻它会长出一个新的叶子节点。每个节点上有一个可爱的小精灵,新长出的节点上也会同时出现一个新的小精灵。小精灵是很萌但是也很脆弱的生物,每个小精灵 i 都有一个感受能力值Ri ,小精灵 i, j 成为朋友当且仅当在树上 i 和 j 的距离 dist(i,j) ≤ Ri + R! ,其中 dist(i, j)表示在这个树上从 i 到 j 的唯一路径上所有边的边权和。强强和萌萌很好奇每次新长出一个叶子节点之后,这个树上总共有几对朋友。  
我们假定这个树一开始为空,节点按照加入的顺序从 1开始编号。由于强强非常好奇, 你必须在他每次出现新节点后马上给出总共的朋友对数,不能拖延哦。

输入

共有 n + 2 行。 
第一行包含一个正整数,表示测试点编号。 
第二行包含一个正整数 n ,表示总共要加入的节点数。 
我们令加入节点前的总共朋友对数是 last_ans,在一开始时它的值为0。 
接下来 n 行中第 i 行有三个数 ai, bi, ri,表示节点  i  的父节点的编号为 ai xor (last_ans mod 10^9)   (其中xor 表示异或,mod  表示取余,数据保证这样操作后得到的结果介于 1到i  –  1之间),与父节点之间的边权为 ci,节点 i 上小精灵的感受能力值为r!。 
注意 a1 = c1 = 0,表示 1 号点是根节点,对于 i > 1,父节点的编号至少为1。

输出

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

样例输入

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

样例输出

0
1
2
4
7


题解

替罪点分树套SBT

如果不考虑插入新点位置(即可以离线把树建出来),只考虑查询的话,那么就相当于查询$dis(i,j)\ge r_i+r_j$,即$dis(i,j)-r_j\ge r_i$的点$j$有多少个。

考虑点分治,一个点的子树中某子节点子树以外的节点到该子节点子树中某点的距离,可以看作先到根节点,再从根节点到这个点。所以可以使用容斥的方法,用所有的点减去在该子树内的点,维护某子树中所有点的$dis(x,rt)-r$,和某子树中所有点的$dis(x,fa[rt])-r$,在查找时,即找出$dis-r\ge r_i-dis(i,rt)$的所有点,于是使用平衡树SBT维护这两个信息,并在平衡树里查找即可。

然而本题强制在线,因此不能把整棵点分树建出来然后处理询问。

这时就可以使用替罪羊树“替罪”的思想,当距离偏差大的时候暴力重构。这样就可以维护一个近似平衡的分治结构以处理询问。

对于每个加点操作,直接把它挂到父亲节点之下,并向上更新子树信息。如果失衡,则找到最上端的替罪节点,重构这棵树。由于点分树的子树就是原树的连通块结构,因此可以直接对这部分建出点分树以重构。

实现起来稍微有点复杂,可以使用vector什么的减小代码复杂度。

查询时按照上面的方法查询即可,需要使用倍增LCA求两点距离。

时间复杂度$O(n\log^3n)=O(能过)$

还是需要内存回收之类的保证空间复杂度。

#include <queue>
#include <cstdio>
#include <vector>
#include <algorithm>
#define N 100010
using namespace std;
struct sbt
{
int w , ls , rs , si;
}a[20000010];
queue<int> q;
vector<int> c[N];
int head[N] , to[N << 1] , next[N << 1] , cnt , fa[N][20] , len[N] , deep[N] , log[N];
int r[N] , pre[N] , si[N] , mx[N] , sum , root , ra[N] , rb[N] , vis[N];
long long ans;
void add(int x , int y)
{
to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
}
void zig(int &k)
{
int t = a[k].ls;
a[k].ls = a[t].rs , a[t].rs = k , a[t].si = a[k].si , a[k].si = a[a[k].ls].si + a[a[k].rs].si + 1;
k = t;
}
void zag(int &k)
{
int t = a[k].rs;
a[k].rs = a[t].ls , a[t].ls = k , a[t].si = a[k].si , a[k].si = a[a[k].ls].si + a[a[k].rs].si + 1;
k = t;
}
void maintain(int &k , bool flag)
{
if(!flag)
{
if(a[a[a[k].ls].ls].si > a[a[k].rs].si) zig(k);
else if(a[a[a[k].ls].rs].si > a[a[k].rs].si) zag(a[k].ls) , zig(k);
else return;
}
else
{
if(a[a[a[k].rs].rs].si > a[a[k].ls].si) zag(k);
else if(a[a[a[k].rs].ls].si > a[a[k].ls].si) zig(a[k].rs) , zag(k);
else return;
}
maintain(a[k].ls , 0) , maintain(a[k].rs , 1);
maintain(k , 0) , maintain(k , 1);
}
void insert(int &k , int x)
{
if(!k) k = q.front() , q.pop() , a[k].w = x , a[k].si = 1;
else
{
a[k].si ++ ;
if(x < a[k].w) insert(a[k].ls , x);
else insert(a[k].rs , x);
maintain(k , x >= a[k].w);
}
}
int find(int k , int x)
{
if(!k) return 0;
else if(x <= a[k].w) return find(a[k].ls , x) + a[a[k].rs].si + 1;
else return find(a[k].rs , x);
}
void del(int &k)
{
if(!k) return;
del(a[k].ls) , del(a[k].rs);
a[k].w = a[k].si = 0 , q.push(k) , k = 0;
}
int lca(int x , int y)
{
int i;
if(len[x] < len[y]) swap(x , y);
for(i = log[len[x] - len[y]] ; ~i ; i -- )
if(len[x] - len[y] >= (1 << i))
x = fa[x][i];
if(x == y) return x;
for(i = log[len[x]] ; ~i ; i -- )
if(len[x] >= (1 << i) && fa[x][i] != fa[y][i])
x = fa[x][i] , y = fa[y][i];
return fa[x][0];
}
int dis(int x , int y)
{
return deep[x] + deep[y] - 2 * deep[lca(x , y)];
}
int query(int x)
{
int i , ans = 0;
for(i = x ; i ; i = pre[i])
ans += find(ra[i] , dis(x , i) - r[x]);
for(i = x ; pre[i] ; i = pre[i])
ans -= find(rb[i] , dis(x , pre[i]) - r[x]);
return ans;
}
void dfs(int x , int fa , int p)
{
int i;
si[x] = 1 , c[p].push_back(x) , insert(ra[p] , r[x] - dis(x , p));
if(pre[p]) insert(rb[p] , r[x] - dis(x , pre[p]));
for(i = head[x] ; i ; i = next[i])
if(!vis[to[i]] && to[i] != fa)
dfs(to[i] , x , p) , si[x] += si[to[i]];
}
void getroot(int x , int fa)
{
int i;
si[x] = 1 , mx[x] = 0;
for(i = head[x] ; i ; i = next[i])
if(!vis[to[i]] && to[i] != fa)
getroot(to[i] , x) , si[x] += si[to[i]] , mx[x] = max(mx[x] , si[to[i]]);
mx[x] = max(mx[x] , sum - si[x]);
if(mx[x] < mx[root]) root = x;
}
void solve(int x , int from)
{
int i;
del(ra[x]) , del(rb[x]) , c[x].clear();
pre[x] = from , vis[x] = 1 , dfs(x , 0 , x);
for(i = head[x] ; i ; i = next[i])
if(!vis[to[i]])
sum = si[to[i]] , root = 0 , getroot(to[i] , 0) , solve(root , x);
}
void join(int x)
{
int i , last = -1;
for(i = x ; i ; i = pre[i])
{
c[i].push_back(x) , insert(ra[i] , r[x] - dis(x , i));
if(pre[i]) insert(rb[i] , r[x] - dis(x , pre[i]));
si[i] ++ ;
if(pre[i] && si[i] * 4 > (si[pre[i]] + 1) * 3) last = pre[i];
}
if(~last)
{
for(i = 0 ; i < (int)c[last].size() ; i ++ ) vis[c[last][i]] = 0;
sum = si[last] , root = 0 , getroot(last , 0) , solve(root , pre[last]);
}
}
int main()
{
int n , i , j , f , b;
for(i = 1 ; i <= 20000000 ; i ++ ) q.push(i);
scanf("%*d%d%*d%*d%d" , &n , &r[1]);
puts("0");
insert(ra[1] , r[1]) , c[1].push_back(1) , si[1] = vis[1] = 1 , mx[0] = 1 << 30;
for(i = 2 ; i <= n ; i ++ )
{
scanf("%d%d%d" , &f , &b , &r[i]) , f ^= (ans % 1000000000) , log[i] = log[i >> 1] + 1 , vis[i] = 1;
fa[i][0] = pre[i] = f , len[i] = len[f] + 1 , deep[i] = deep[f] + b;
add(f , i) , add(i , f);
for(j = 1 ; (1 << j) <= len[i] ; j ++ ) fa[i][j] = fa[fa[i][j - 1]][j - 1];
ans += query(i) , printf("%lld\n" , ans);
join(i);
}
return 0;
}

【bzoj3435】[Wc2014]紫荆花之恋 替罪点分树套SBT的更多相关文章

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

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

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

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

  3. BZOJ3435: [Wc2014]紫荆花之恋(替罪羊树,Treap)

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

  4. bzoj3435 [Wc2014]紫荆花之恋

    如果这棵树不变的话,就是一个裸的点分树套平衡树,式子也很好推$di+dj<=ri+rj$,$ri-di>=dj-rj$ 平衡树维护$dj-rj$,然后查$ri-di$的$rank$即可. ...

  5. bzoj3435 [Wc2014]紫荆花之恋(动态点分治+替罪羊树)

    传送门(权限) 传送门(非权限) 题解 我终终终终终终于做出来啦!!! 作为一个没有学过替罪羊树的蒟蒻现场学了一下替罪羊树,作为一个平衡树都写数组版本的看着大佬的指针题解无语只能硬去理解然后照着抄了一 ...

  6. luoguP3920 [WC2014]紫荆花之恋 动态点分治 + 替罪羊树

    意外的好写..... 考虑点分 \(dis(i, j) \leq r_i + r_j\) 对于过分治中心一点\(u\),有 \(dis(i, u) - r_i = dis(j, u) + r_j\) ...

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

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

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

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

  9. BZOJ3435 & 洛谷3920 & UOJ55:[WC2014]紫荆花之恋

    https://www.lydsy.com/JudgeOnline/problem.php?id=3435 https://www.luogu.org/problemnew/show/P3920 ht ...

随机推荐

  1. 浅谈KD-Tree

    前言 \(KD-Tree\)是一个十分神奇的东西,其实本质上类似于一个\(K\)维的二叉搜索树. 核心思想 \(KD-Tree\)的核心思想与\(BST\)是差不多的(插入等操作也都基本上一样). 唯 ...

  2. 2dsphere索引

    概念:球面地理位置索引 创建方式: db.collection.ensureIndex({w:'2dsphere'}) wdspere中,位置的表示方式不再是简单的经度,纬度,数组,而是变成一种复杂的 ...

  3. 2018.6.5 Oracle plsql编程 游标的使用

    --3.查询10部门所有员工的姓名.(ref游标实现) 动态游标 declare --创建一种游标类型 type type_cursor is ref cursor; --声明变量指定游标类型 v_c ...

  4. python_输入一个数,判断是否是素数

    while True: n=int(input('n=')) for i in range(2,n): if n%i==0: print("n is not 素数") break ...

  5. scikit-learn 中 OneHotEncoder 解析

    概要 在 sklearn 包中,OneHotEncoder 函数非常实用,它可以实现将分类特征的每个元素转化为一个可以用来计算的值.本篇详细讲解该函数的用法,也可以参考官网 sklearn.prepr ...

  6. python 线程的调用方式

    python 线程的调用方式 #!/usr/bin/env python #-*- coding:utf-8 -*- # author:leo # datetime:2019/5/24 9:44 # ...

  7. 基础I/O

    基础IO: c库文件IO操作接口:(详细查看c语言中的文件操作函数总结:https://www.cnblogs.com/cuckoo-/p/10560640.html) fopen 打开文件 fclo ...

  8. java面试题:如果一串字符如"aaaabbc中国1512"要分别统计英文字符的数量,中文字符的数量,和数字字符的数量,假设字符中没有中文字符、英文字符、数字字符之外的其他特殊字符。

    package com.swift; public class TotalNumber_String { public static void main(String[] args) { /* * 如 ...

  9. Symmetric Difference-freecodecamp算法题目

    Symmetric Difference 1.要求 创建一个函数,接受两个或多个数组,返回所给数组的对等差分(symmetric difference) 例子:给出两个集合 (如集合 A = {1, ...

  10. leetcode笔记(一)309. Best Time to Buy and Sell Stock with Cooldown

    题目描述 (原题目链接) Say you have an array for which the ith element is the price of a given stock on day i. ...