意外的好写.....


考虑点分

\(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. Python案例

    我感觉好方啊,Python和C语言不一样啊....写了几个例子... 变量    变量的占位后面没有逗号啊啊啊啊 name='张泉' age=22 tel=110 print ('姓名:%s,年龄:% ...

  2. Struts2_day01

    一.内容大纲 1 struts2概述 (1)应用在web层 2 struts2入门案例 3 struts2底层执行过程 4 struts2相关配置 (1)struts.xml配置 - package. ...

  3. CSS规范 - 命名规则--(来自网易)

    使用类选择器,放弃ID选择器 ID在一个页面中的唯一性导致了如果以ID为选择器来写CSS,就无法重用. NEC特殊字符:"-"连字符 "-"在本规范中并不表示连 ...

  4. 禁止表单操作及JS控制输入的方式

    <div>表单元素特殊属性<input type="text" value="禁止输入" disabled /></div> ...

  5. [Alg::Trick]小白鼠找毒酒

    题目来源:牛客网 https://www.nowcoder.com/questionTerminal/c26c4e43c77440ee9497b20118871bf1 8瓶酒一瓶有毒,用人测试.每次测 ...

  6. git merge branch to master

    git checkout master git pull git merge testbranch git push

  7. asp.net动态增加服务器端控件并提交表单

    为什么要用原生的呢? 1.目的 原生出现浏览器兼容性问题 极少,不用测试多浏览兼容性 .需要考虑到市面上的其他垃圾浏览器. 2.性能不好 如果不考虑第一条 你可以换一种方式 直接上代码 .aspx页面 ...

  8. [转]html网页 swf播放器使用代码

    <object id="player" height="240" width="275" classid="CLSID:6B ...

  9. sys和os模块

    一 sys 用于python解释器相关的操作 #!/usr/bin/env python # coding=utf-8 import time import sys def view_bar(num, ...

  10. Android 6.0 变更

    Android 6.0(API 级别 23)除了提供诸多新特性和功能外,还对系统和 API 行为做出了各种变更.本文重点介绍您应该了解并在开发应用时加以考虑的一些主要变更. 如果您之前发布过 Andr ...