关于求答案:
对于每一个分治中心 g g g,求经过它的点对 ( u , v ) (u,v) (u,v) 的贡献
需要 d i s ( u , g ) + d i s ( v , g ) ≤ r u + r v dis(u,g)+dis(v,g)\le r_u+r_v dis(u,g)+dis(v,g)≤ru+rv
也就是 d i s ( u , g ) − r u ≤ r v − d i s ( v , g ) dis(u,g)-r_u\le r_v-dis(v,g) dis(u,g)−ru≤rv−dis(v,g)
可以用平衡树维护一波 d i s ( u , g ) − r u dis(u,g)-r_u dis(u,g)−ru,然后就是查询比一个数小的个数
但这样是算重了的,因为 u , v u,v u,v 可能在 g g g 下方的同一棵子树
然后还需要维护一棵减去贡献的平衡树
不用想复杂,减去的贡献 ( u , v ) (u,v) (u,v) 当且仅当 ( u , v ) (u,v) (u,v) 在切掉 g g g 的情况下还在一个联通块
于是可以对这些连通块维护平衡树存同样的值
也就是说当前点 u u u 的贡献,就是在每一个祖先 g g g 查一个答案,然后在 g g g 割掉后 u u u 的联通块的平衡树中查一个答案减掉
为了避免点分树每次跳 f a fa fa 的繁琐讨论
我们每个点开一个 v e c t o r vector vector 存 ( f a , d i s , t r e e ) (fa,dis,tree) (fa,dis,tree)
表示这个点的祖先,到祖先的距离以及切掉祖先后 u u u 所在的平衡树的编号
因为要插叶子,所以点分树会不平衡,类似替罪羊的思想,设一个平衡因子 α \alpha α,定期重构
重构点分树:
首先需要知道支持这个重构操作需要维护什么?
子树需要清空,每个点开 v e c t o r vector vector 暴力维护子树中的结点
然后对于一个子孙的 ( f a , d i s , t r e e ) (fa,dis,tree) (fa,dis,tree) 的 t r e e tree tree 我们需要把它清空,所以一个点要维护切掉它过后的 t r e e tree tree 的集合,同样 v e c t o r vector vector 暴力维护
需要清空的东西:
1.子树所有点的平衡树
2.子树所有点维护儿子的 v e c t o r vector vector
3.子树用来减的平衡树
4.子树所有维护祖先的 v e c t o r vector vector
5.维护割掉它剩下的联通块的平衡树
细节:发现祖先的 v e c t o r vector vector 是按顺序插的,深的在下面,于是弹一个点的祖先的时候可以暴力弹的 x x x
点分治
跟一般的点分治一样, d f s dfs dfs 的时候插一下维护祖先的 v e c t o r vector vector
然后暴力把 d f s dfs dfs 到的点插到自己的儿子集合,把 r i − d i s r_i-dis ri−dis 存下来平衡树 b u i l d build build 一波
然后还要维护一圈的平衡树,把那一棵子树的点弄出来暴力 b u i l d build build 就可以了
插入:
把 x x x 挂在 u u u 上
先把 u u u 维护祖先的 v e c t o r vector vector 复制给 x x x,然后将里面的每一个 d i s dis dis 加上 d i s ( x , u ) dis(x,u) dis(x,u)
在祖先 g g g 的平衡树中插入 d i s − r x dis - r_x dis−rx 的值
然后需要在 x x x 的 v e c t o r vector vector 中插入 ( u , d i s ( x , u ) , t r e e ) (u,dis(x,u),tree) (u,dis(x,u),tree) 这个三元组
然后暴力跳祖先,把 x x x 加到它们的集合
中途遇到不平衡就找到最高的并重构
总结:
再次理清思路:
主要细节就是这些,第一个特判
平衡树随便选一个就可以了
#include
#define cs const
using namespace std;
int read(){
int cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1;}
while(isdigit(ch)) cnt = (cnt << 1) + (cnt << 3) + (ch-'0'), ch = getchar();
return cnt * f;
}
typedef long long ll;
cs double alpha = 0.8;
cs int N = 2e5 + 5, M = 6e6 + 5;
cs int mod = 1e9;
int TEST, n, r[N];
ll ans;
namespace SBT{ // 替罪羊
int ch[M][2], fa[M], siz[M], val[M]; int node;
int sta[M], top;
int a[M], hd;
#define ls ch[x][0]
#define rs ch[x][1]
int ck(){ return top ? sta[top] : node + 1; }
int newnode(){ return top ? sta[top--] : ++node; }
void bin(int x){ ls = rs = 0; sta[++top] = x;}
void pia(int x){ if(ls) pia(ls); if(rs) pia(rs); bin(x); }
int gc(int x){ return ch[fa[x]][1] == x; }
struct sbt{
int rt;
void re(int x){ if(ls) re(ls); a[++hd] = x; if(rs) re(rs); }
void pushup(int x){ siz[x] = siz[ls] + siz[rs] + 1; }
int build(int l, int r){
if(l > r) return 0; int mid = (l+r) >> 1, x = a[mid];
ls = build(l, mid - 1); rs = build(mid + 1, r);
fa[ls] = fa[rs] = x; pushup(x); return x;
}
void ins(int v){
int hi = -1, p = 0;
for(int x = rt; x; x = ch[p][val[p] <= v]){
p = x; ++siz[p]; if(fa[p] && fa[p] != rt && hi == -1 && siz[fa[p]] * 4 <= siz[p] * 5) hi = fa[p];
} int nx = newnode(); fa[nx] = p; ch[p][val[p] <= v] = nx; val[nx] = v; siz[nx] = 1;
// rebuild
if(hi != -1){ int f = fa[hi]; int k = gc(hi); hd = 0; re(hi); ch[f][k] = build(1, hd); fa[ch[f][k]] = f; }
}
int query(int v){
int ans = 0; for(int x = rt; x;){
if(val[x] <= v) ans += siz[ls] + 1, x = rs;
else x = ls;
} return ans;
}
int rebuild(int *a, int l, int r){
if(l > r) return 0; int mid = (l+r) >> 1; int x = newnode(); val[x] = a[mid];
ls = rebuild(a, l, mid - 1); rs = rebuild(a, mid + 1, r);
fa[ls] = fa[rs] = x; pushup(x); return x;
}
void clear(){pia(rt);}
void INIT(int *a, int len){ rt = rebuild(a, 0, len); fa[rt] = 0; }
};
}
namespace TREE{
int first[N], nxt[N], to[N], w[N], tot;
void add(int x, int y, int z){
nxt[++tot] = first[x], first[x] = tot, to[tot] = y, w[tot] = z;
}
int ndep[N];
vector<int> son[N];
struct data{
int fa, dis; SBT::sbt T;
}; vector<data> v[N];
typedef vector<data>::iterator Data;
typedef vector<int>::iterator Int;
typedef vector<SBT::sbt>::iterator Sbt;
vector<SBT::sbt> nw[N];
SBT::sbt T[N];
int top, *mdep, ret;
int siz[N], mxson[N];
bool cut[N];
int rt;
void getsz(int u, int fa){
siz[u] = 1;
for(int i = first[u]; i; i = nxt[i]){
int t = to[i]; if(t == fa || !cut[t]) continue;
getsz(t, u); siz[u] += siz[t];
}
}
void getrt(int u, int fa, int S){
mxson[u] = 0;
for(int i = first[u]; i; i = nxt[i]){
int t = to[i]; if(t == fa || !cut[t]) continue;
getrt(t, u, S); mxson[u] = max(mxson[u], siz[t]);
} mxson[u] = max(mxson[u], S - siz[u]);
if(mxson[rt] > mxson[u]) rt = u;
}
void dfs(int u, int fa, int dis, int g, int p){
son[g].push_back(u); v[u].push_back((data){g, dis, (SBT::sbt){p}});
mdep[++top] = dis - r[u];
for(int i = first[u]; i; i = nxt[i]){
int t = to[i]; if(t == fa || !cut[t]) continue;
dfs(t, u, dis + w[i], g, p);
}
}
void solve(int x){
getsz(x, 0); rt = 0; getrt(x, 0, siz[x]); int g = rt; cut[g] = false;
son[g].clear(); son[g].push_back(g);
if(siz[x] == 1){ ndep[0] = -r[x]; T[g].INIT(ndep, 0); return; }
mdep = ndep; top = -1; int Siz = 0;
for(int i = first[g]; i; i = nxt[i]){
if(!cut[to[i]]) continue; mdep = mdep + top + 1;
Siz += top + 1;
top = -1;
dfs(to[i], g, w[i], g, SBT::ck());
SBT::sbt tr; sort(mdep, mdep + top + 1);
tr.INIT(mdep, top); nw[g].push_back(tr);
} Siz += top + 1; ndep[Siz] = -r[g]; sort(ndep, ndep + Siz + 1);
T[g].INIT(ndep, Siz);
for(int i = first[g]; i; i = nxt[i]) if(cut[to[i]]) solve(to[i]);
}
void rebuild(int x){
for(Int it = son[x].begin(); it != son[x].end(); it++) cut[*it] = true;
for(Int it = son[x].begin(); it != son[x].end(); it++) T[*it].clear(); // 清空子树的平衡树
for(Int it = son[x].begin(); it != son[x].end(); it++){ // 清空子树所有点周围的平衡树
for(Sbt it1 = nw[*it].begin(); it1 != nw[*it].end(); it1++){
it1->clear();
} nw[*it].clear();
}
for(Int it = son[x].begin(); it != son[x].end(); it++){ // 清空子树中所有点存的祖先
if(*it != x){
while(1){
if(v[*it].rbegin()->fa == x){ // fa 是按顺序插入的
v[*it].pop_back(); break;
} else v[*it].pop_back();
}
}
} solve(x);
}
int ins(int x, int fa, int d, int wi){
add(x, fa, d); add(fa, x, d);
v[x] = v[fa];
for(Data it = v[x].begin(); it != v[x].end(); it++){
it->dis += d;
it->T.ins(it->dis - wi);
T[it->fa].ins(it->dis - wi);
}
SBT::sbt tr;
ndep[0] = d - wi;
tr.INIT(ndep, 0);
v[x].push_back((data){fa, d, tr});
nw[fa].push_back(tr);
T[fa].ins(d - wi);
ndep[0] = - wi;
T[x].INIT(ndep, 0);
son[x].push_back(x);
for(Data it = v[x].begin(); it != v[x].end(); ++it) son[it->fa].push_back(x);
Data it1 = v[x].begin(), it2 = it1; ++it2;
for(;it2 != v[x].end(); ++it2, ++it1){
if(son[it2->fa].size() * 5 >= son[it1->fa].size() * 4){ rebuild(it1->fa); break; }
}
int ans = T[x].query(wi) - 1; // 到 p 的点单独查
for(Data it = v[x].begin(); it != v[x].end(); ++it)
ans += T[it->fa].query(wi - it->dis) - it->T.query(wi - it->dis);
return ans;
}
void INIT(int wi){
ndep[0] = -wi; T[1].INIT(ndep, 0); son[1].push_back(1);
}
}
int main(){
TEST = read();
n = read();
TREE::mxson[0] = n + 1;
for(int i = 1; i <= n; i++){
ll fa = (read() ^ (ans % mod)), d = read(); r[i] = read();
if(i == 1){ TREE::INIT(r[i]); puts("0"); continue; }
ans += (ll)TREE::ins(i, fa, d, r[i]); cout << ans << '\n';
} return 0;
}