数据结构(平衡树,树分治,暴力重构):WC 2014 紫荆花之恋

时间:2023-11-25 22:18:14

【题目描述】

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

仔细看看的话,这棵大树实际上是一个带权树。每个时刻他会长出一个新的叶子节点。每个节点上有一个可爱的小精灵,新长出的节点上也会同时出现一个新的小精
灵。小精灵是很萌但是也很脆弱的生物,每个小精灵i都有一个感受能力ri,小精灵i,j成为朋友当且仅当在树上i和j的距离
dist(i,j)<=ri+rj,其中dist(i,j)表示在这棵树上i和j的唯一路径上所有边的边权和。

强强和萌萌很好奇每次新长出了一个叶子节点之后这棵树上总共有几对朋友。

我们假定这棵树一开始为空,节点按照加入的顺序从1开始编号。由于强强非常好奇,你必须在每次出现新的节点后马上给出总共的朋友对数不能拖延哦。

【输入格式】

输入文件共有n+2行。

第一行包含一个正整数T,表示测试点编号。

第二行包含一个正整数n,表示总共要加入的节点数。

我们令加入前的总工朋友对数是last_ans,在一开始时last_ans=0。

接下来n行中第i行有三个数ai,ci,ri,表示节点i的父亲节点的编号为(ai xor ( last_ans mod 10^9)),与父亲节点之间的边权为ci,节点i上小精灵的感受能力为ri。

注意a1=c1=0,表示1号点事根节点。对于i>=2,父亲节点的编号至少是1,至多是i-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   对于每一对点,通过之间路径的最高点更新答案,枚举最高点(log)用平衡树维护并查找(log),但是不断新加点会导致树高太大,算法退化。这时发现用点分治的思想把树划分,得到一棵新树,若维护了现在每个点到根节点路径上每个dep的距离,还是一样的可以求得答案,这样重新构建树可以解决退化问题。
  发现自己的代码很短,其实有什么10行AC代码,但事实上还是这个算法。
 #include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
using namespace std;
const int N=,M=;
int cnt,fir[N],to[N*],val[N*],nxt[N*];
void addedge(int a,int b,int v){
nxt[++cnt]=fir[a];
to[fir[a]=cnt]=b;
val[cnt]=v;
}
int pim,top,pool[N],sz[M];
int ch[M][],key[M],fix[M];
#define lc ch[x][0]
#define rc ch[x][1]
int Newnode(int k){
int x=top?pool[top--]:++pim;
sz[x]=;lc=rc=;key[x]=k;
fix[x]=rand();return x;
}
#define c (k>=key[x])
#define g ch[x][c] void Push_up(int x){sz[x]=sz[lc]+sz[rc]+;} void Rotate(int x,int &y,int f){
ch[y][f]=ch[x][f^];ch[x][f^]=y;
Push_up(y);Push_up(x);y=x;
} void Insert(int &x,int k){
if(!x){x=Newnode(k);return;}Insert(g,k);
sz[x]+=;if(fix[x]>fix[g])Rotate(g,x,c);
} int Query(int x,int k){
if(!x)return ;
if(!c)return Query(g,k);
return Query(g,k)+sz[lc]+;
} void Delete(int &x){
if(!x)return;
pool[++top]=x;x=;
if(lc)Delete(lc);
if(rc)Delete(rc);
} long long ans;
int n,fa[N],v[N],r[N];
int rt[N],pt[N],dep[N];
int G[N][],SZ[N],P,w,tp;
int F[N],H[N],S,mm; void Get_G(int x,int f,int d){
F[x]=H[x]=;
for(int i=fir[x];i;i=nxt[i])
if(to[i]!=f&&dep[to[i]]>=d){
Get_G(to[i],x,d);
H[x]=max(H[x],F[to[i]]);
F[x]+=F[to[i]];
}
H[x]=max(H[x],S-F[x]);
if(!P||H[P]>H[x])P=x;
} void DFS(int x,int f,int d,int v,int &t){
F[x]=;dep[x]=d+;
G[x][d]=v;Insert(t,v-r[x]);
for(int i=fir[x];i;i=nxt[i])
if(to[i]!=f&&dep[to[i]]>=d){
DFS(to[i],x,d,v+val[i],t);
F[x]=F[x]+F[to[i]];
}
} void Rebuild(int x,int f,int d,int m,int sz){
P=;S=sz;Get_G(x,,d);fa[x=P]=f;Delete(rt[x]);
SZ[x]=sz;DFS(x,,d,,rt[x]);dep[x]=d;
if(pt[x]!=mm)Delete(pt[x]);pt[x]=m;
for(int i=fir[x],p;i;i=nxt[i])
if(dep[to[i]]>=d){
p=;DFS(to[i],,d+,val[i],p);
Rebuild(to[i],x,d+,p,F[to[i]]);
}
} int main(){
freopen("flowera.in","r",stdin);
freopen("flowera.out","w",stdout);
scanf("%d%d",&tp,&n);
scanf("%d%d%d",fa+,v+,r+);
Insert(rt[],-r[]);SZ[]=;puts("");
for(int x=;x<=n;x++){
scanf("%d%d%d",fa+x,v+x,r+x);
fa[x]^=ans%;
addedge(x,fa[x],v[x]);
addedge(fa[x],x,v[x]);
dep[x]=dep[fa[x]]+; for(int i=;i<dep[x];i++)
G[x][i]=G[fa[x]][i]+v[x]; for(int y=x;y!=;y=fa[y]){
SZ[y]+=;w=r[x]-G[x][dep[y]];
ans+=Query(rt[y],w);
Insert(rt[y],-w);
if(fa[y]){
w=r[x]-G[x][dep[fa[y]]];
ans-=Query(pt[y],w);
Insert(pt[y],-w);
if(SZ[y]>SZ[fa[y]]*.)P=fa[y];
}
}
printf("%lld\n",ans);
if(P)Rebuild(P,fa[P],dep[P],mm=pt[P],SZ[P]),P=;
}
return ;
}