意外的好写.....


考虑点分

\(dis(i, j) \leq r_i + r_j\)

对于过分治中心一点\(u\),有

\(dis(i, u) - r_i = dis(j, u) + r_j\)

对于同一子树内需要去重

原本是考虑用值域线段树来维护的,看了看\(10^9\)的范围,空间估计开不下

那就用平衡树吧...


用动态点分来维护答案,每次默认把\(i\)归到父亲的分治结构中

如果某个分治结构过于不平衡,那么就暴力重构

注意一下,一个点分治中的分治结构在树中对应一个联通块,没有任何其他的性质...

(我用\(n \log n\)的时间直接暴力维护了,感觉应该有更好的办法)

和二叉树的分析差不多,复杂度是\(O(n \log^2 n)\)的吧...


一开始受到了打树静态的动态点分治的影响

对于分治中心\(u\),直接把每个子树的信息存在了和\(u\)有对应连边的点上...

事实上,应该存在对应子树的重心上,重构的时候才不会出错...


#include <map>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; #define ll long long
#define ri register int
#define rep(io, st, ed) for(ri io = st; io <= ed; io ++)
#define drep(io, ed, st) for(ri io = ed; io >= st; io --) #define gc getchar
inline int read() {
int p = 0, w = 1; char c = gc();
while(c > '9' || c < '0') { if(c == '-') w = -1; c = gc(); }
while(c >= '0' && c <= '9') p = p * 10 + c - '0', c = gc();
return p * w;
} const int sid = 3e5 + 5;
const int cid = 5e6 + 5; struct stO_Mxl_Orz { int trash[cid], id, top; struct Yume_Alive_Forever {
int sz, pri, num, son[2];
ll val;
} t[cid]; inline int rand() {
static int seed = 23333333;
return seed = (seed * 97103LL) % 2147483647;
} #define ls(o) t[(o)].son[0]
#define rs(o) t[(o)].son[1] inline int newnode(ll v) {
int ip = top ? trash[top --] : ++ id;
ls(ip) = rs(ip) = 0; t[ip].sz = t[ip].num = 1;
t[ip].val = v; t[ip].pri = rand();
return ip;
} inline void upd(int o) {
t[o].sz = t[ls(o)].sz + t[rs(o)].sz + t[o].num;
} inline void recycle(int &o) {
if(!o) return;
recycle(ls(o)); recycle(rs(o));
trash[++ top] = o;
} inline void rotate(int &o, int p) {
int u = t[o].son[p];
t[o].son[p] = t[u].son[!p]; t[u].son[!p] = o;
upd(o); upd(u); o = u;
} inline void insert(int &o, ll v) {
if(!o) { o = newnode(v); return; }
t[o].sz ++;
if(v == t[o].val) { t[o].num ++; return; }
int nxt = v > t[o].val;
insert(t[o].son[nxt], v);
if(t[o].pri > t[t[o].son[nxt]].pri) rotate(o, nxt);
} inline int qry(int o, ll v) {
if(!o) return 0;
if(v == t[o].val) return t[ls(o)].sz + t[o].num;
if(v < t[o].val) return qry(ls(o), v);
else return t[ls(o)].sz + t[o].num + qry(rs(o), v);
} } myk; bool debug; ll dit[sid];
int dep[sid], up[sid][17];
inline int lca(int u, int v) {
if(dep[u] < dep[v]) swap(u, v);
int d = dep[u] - dep[v];
drep(i, 16, 0) if(d & (1 << i)) u = up[u][i];
if(u == v) return u;
drep(i, 16, 0)
if(up[u][i] != up[v][i]) u = up[u][i], v = up[v][i];
if(u == v) return u;
return up[u][0];
} inline ll dis(int u, int v) {
return dit[u] + dit[v] - (dit[lca(u, v)] << 1);
} ll ans;
int r[sid], fa[sid];
int msx[sid], fd[sid], rt[sid], lrt[sid]; int asz, cnp, tim, hrt, ban;
int son[sid], sz[sid], ok[sid], vis[sid];
int cap[sid], nxt[sid], node[sid], len[sid]; inline void addedge(int u, int v, int w) {
nxt[++ cnp] = cap[u]; cap[u] = cnp; node[cnp] = v; len[cnp] = w;
nxt[++ cnp] = cap[v]; cap[v] = cnp; node[cnp] = u; len[cnp] = w;
} #define cur node[i]
inline void grt(int o, int fa) {
son[o] = 0; sz[o] = 1;
for(int i = cap[o]; i; i = nxt[i])
if(ok[cur] == tim && vis[cur] != tim && cur != fa) {
grt(cur, o); sz[o] += sz[cur];
if(sz[cur] > son[o]) son[o] = sz[cur];
}
son[o] = max(son[o], asz - son[o]);
if(son[o] < son[hrt]) hrt = o;
} inline void dfs(int o, int fa) {
sz[o] = 1;
for(int i = cap[o]; i; i = nxt[i])
if(ok[cur] == tim && vis[cur] != tim && cur != fa)
dfs(cur, o), sz[o] += sz[cur];
} vector <int> as[sid];
inline void dfs(int o, int fa, int anc1, int anc2, ll lev) {
as[anc2].push_back(o);
myk.insert(rt[anc2], lev - r[o]);
myk.insert(lrt[anc1], lev - r[o]);
for(int i = cap[o]; i; i = nxt[i])
if(ok[cur] == tim && vis[cur] != tim && cur != fa)
dfs(cur, o, anc1, anc2, lev + len[i]);
} inline void solve(int o) {
vis[o] = tim;
as[o].push_back(o);
myk.insert(rt[o], - r[o]);
for(int i = cap[o]; i; i = nxt[i])
if(ok[cur] == tim && vis[cur] != tim && cur != ban) dfs(cur, o);
msx[o] = 0;
for(int i = cap[o]; i; i = nxt[i])
if(ok[cur] == tim && vis[cur] != tim) {
msx[o] = max(msx[o], sz[cur]);
asz = sz[cur]; hrt = 0;
grt(cur, o); fd[hrt] = o;
dfs(cur, o, hrt, o, len[i]);
solve(hrt);
}
} inline void dfs(int o, int fa, int anc) {
as[o].clear();
myk.recycle(rt[o]); rt[o] = 0;
myk.recycle(lrt[o]); lrt[o] = 0;
if(ban) myk.insert(lrt[anc], dis(o, ban) - r[o]);
for(int i = cap[o]; i; i = nxt[i])
if(ok[cur] == tim && cur != ban && cur != fa)
dfs(cur, o, anc);
} inline void rebuild(int o) {
++ tim; ban = fd[o];
asz = myk.t[rt[o]].sz; hrt = 0;
for(auto x : as[o]) ok[x] = tim;
grt(o, ban);
dfs(hrt, ban, hrt);
fd[hrt] = ban;
solve(hrt);
} inline void modify(int o) {
fd[o] = fa[o];
for(ri now = fd[o], lst = o; now; lst = now, now = fd[now]) {
ll v = dis(now, o);
as[now].push_back(o);
myk.insert(rt[now], v - r[o]);
myk.insert(lrt[lst], v - r[o]);
ans += myk.qry(rt[now], r[o] - v) - myk.qry(lrt[lst], r[o] - v);
msx[now] = max(msx[now], myk.t[lrt[lst]].sz);
} const double Yume_Saiko = 0.756412; int tmp = -1;
for(ri now = fd[o]; now; now = fd[now])
if(msx[now] >= myk.t[rt[now]].sz * Yume_Saiko) tmp = now;
if(tmp != -1) rebuild(tmp);
} const int mod = 1e9;
int main() {
int Wahaha = read();
int n = read(); son[0] = n + 1;
for(ri i = 1; i <= n; i ++) {
fa[i] = read() ^ (ans % mod);
int c = read(); r[i] = read(); addedge(fa[i], i, c);
up[i][0] = fa[i];
dep[i] = dep[fa[i]] + 1;
dit[i] = dit[fa[i]] + c;
for(ri j = 1; j <= 16; j ++)
up[i][j] = up[up[i][j - 1]][j - 1]; as[i].push_back(i);
myk.insert(rt[i], -r[i]);
if(i != 1) modify(i);
printf("%lld\n", ans);
}
return 0;
}

luoguP3920 [WC2014]紫荆花之恋 动态点分治 + 替罪羊树的更多相关文章

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

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

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

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

  3. UOJ #55 & 洛谷 P3920 紫荆花之恋 —— 动态点分治+替罪羊树

    题目:http://uoj.ac/problem/55 https://www.luogu.org/problemnew/show/P3920 参考博客:https://www.cnblogs.com ...

  4. uoj 55 紫荆花之恋 动态点分治+替罪羊式重构+treap

    每插入一个点,直接把它当做重心插入原树,当做是动态点分树一样维护 但这样深度会越来越大,所以我们用类似替罪羊的方法 当树失去平衡时,对子树进行一次点分,保证复杂度 #include <cstdi ...

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

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

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

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

  7. 【bzoj3435】[Wc2014]紫荆花之恋 替罪点分树套SBT

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

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

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

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

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

随机推荐

  1. sqlserver运行脚本数据出现 内存不足的解决办法

    但是当数据库导出脚本很大,用Microsoft SQL Server Management Studio执行脚本时,往往会遇到“内存不足”的提示. 解决办法: 用微软自带的sqlcmd工具,可以导入执 ...

  2. html <label>标签

    label元素在呈现上没有特殊效果,但为鼠标用户增进了可用性. 如果在label元素内点击文本,就会触发表单控件. 也就是说,当用户选择该标签时,浏览器就会自动将焦点转到和标签相关的表单控件上. &l ...

  3. JAVA记录-JSP指令

    JSP中有三种类型的指令标签 - 序号 指令 说明 1 <%@ page ... %> 定义页面相关属性,如脚本语言,错误页面和缓冲要求. 2 <%@ include ... %&g ...

  4. Java入门系列(九)Java API

    String,StringBuilder,StringBuffer三者的区别 1.首先说运行速度,或者说是执行速度 在这方面运行速度快慢为:StringBuilder > StringBuffe ...

  5. 用python处理文本,本地文件系统以及使用数据库的知识基础

    主要是想通过python之流的脚本语言来进行文件系统的遍历,处理文本以及使用简易数据库的操作. 本文基于陈皓的:<程序员技术练级攻略> 一.Python csv 对于电子表格和数据库导出文 ...

  6. 20155225 2016-2017-2 《Java程序设计》第八周学习总结

    20155225 2016-2017-2 <Java程序设计>第八周学习总结 教材学习内容总结 通用API 日志API 国际化基础 规则表达式 JDK8增强功能 教材学习中的问题和解决过程 ...

  7. HDU 1005 Number Sequence (模拟)

    题目链接 Problem Description A number sequence is defined as follows: f(1) = 1, f(2) = 1, f(n) = (A * f( ...

  8. 【ORACLE】oracl基本操作笔记

    1.用命令导入导出表 C:\Users\xiang>imp bjlims/bjlims@orcl file="c:\tjlims.dmp" full=y C:\Users\x ...

  9. E1. Array and Segments (Easy version)(暴力) && E2. Array and Segments (Hard version)(线段树维护)

    题目链接: E1:http://codeforces.com/contest/1108/problem/E1 E2:http://codeforces.com/contest/1108/problem ...

  10. 关于v4包的Fragment过渡动画的事件监听无响应问题解决

    项目中部分功能模块采用了单Activity+多Fragment模式,当Fragment切换时,需要在过渡动画执行完后做一些操作,通常就是在自己封装的FragmentBase中重写onCreateAni ...