网上题解都说的很详细了吧
考虑点分治
dist(i,j)≤Ri+Rj
可以转化成
Dj−Rj≤Ri−Di
其中
Di
表示到重心的距离
开两颗平衡树维护 一颗统计 一颗去重
然后 因为要动态加点 点分树的性质不能保证
所以当一个子树的大小超过某个阈值时 就把点分树替罪羊式重构下
说起来真轻巧
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
inline void write(ll x) {
if (!x) return (void)printf("0\n");
static short s[20],t;
while (x) s[++t]=x%10,x/=10; while (t) putchar('0'+s[t--]);
putchar('\n');
}
const int N=100005;
const int K=100;
const double ab=0.75;
namespace SGT{
const int MN=N*K;
struct node{
node *ch[2];
int key,size;
void update() { size=ch[0]->size+ch[1]->size+1; }
bool bad() { return ch[0]->size>=size*ab+5 || ch[1]->size>=size*ab+5; }
}Mem[MN],*null;
node *Stack[MN]; int pnt;
node *lst[MN]; int len;
inline void Init(){
null=Mem; null->size=0; null->ch[0]=null->ch[1]=null;
for (int i=1;i<MN;i++) Stack[++pnt]=Mem+i;
}
inline node *New(int key){
node *t=Stack[pnt--];
t->ch[0]=t->ch[1]=null; t->size=1; t->key=key;
return t;
}
inline void travel(node *p){
if (p==null) return;
travel(p->ch[0]); lst[++len]=p; travel(p->ch[1]);
}
inline node *divide(int l,int r){
if (l>r) return null;
int mid=(l+r)>>1;
lst[mid]->ch[0]=divide(l,mid-1); lst[mid]->ch[1]=divide(mid+1,r); lst[mid]->update();
return lst[mid];
}
inline void rebuild(node *&p){
len=0; travel(p); p=divide(1,len);
}
inline node **insert(node *&p,int key){
if (p==null){ p=New(key); return &null; }
p->size++;
node **ret=insert(p->ch[key>=p->key],key);
if (p->bad()) ret=&p;
return ret;
}
inline int Kth(node *root,int k){
node *p=root;
while (p!=null){
if (k==p->ch[0]->size+1) return p->key;
else if (p->ch[0]->size>=k) p=p->ch[0];
else k-=p->ch[0]->size+1,p=p->ch[1];
}
}
inline int Rank(node *root,int val){
node *p=root; int ret=1;
while (p!=null)
if (p->key>=val)
p=p->ch[0];
else
ret+=p->ch[0]->size+1,p=p->ch[1];
return ret;
}
inline void clear(node *p){
if (p==null) return;
clear(p->ch[0]); Stack[++pnt]=p; clear(p->ch[1]);
}
struct Set{
node *root;
void Init() { root=null; }
inline void Insert(int val){
node **p=insert(root,val);
if (*p!=null) rebuild(*p);
}
void Clear(){
clear(root); root=null;
}
int Query(int x){
return Rank(root,x+1)-1;
}
};
}
SGT::Set sr[N],sf[N];
struct edge{
int u,v,w,next;
}G[N<<1];
int head[N],inum;
inline void add(int u,int v,int w,int p){
G[p].u=u; G[p].v=v; G[p].w=w; G[p].next=head[u]; head[u]=p;
}
#define V G[p].v
int n,val[N];
int cnt[N];
int del[N],clk,flag[N];
int size[N]; int sum,root,minv;
inline void Root(int u,int fa){
size[u]=1; int maxv=0;
for (int p=head[u];p;p=G[p].next)
if (flag[V]==clk && del[V]!=clk && V!=fa)
Root(V,u),size[u]+=size[V],maxv=max(maxv,size[V]);
maxv=max(maxv,sum-size[u]);
if (maxv<minv) minv=maxv,root=u;
}
vector<int> son[N];
int cur;
int fat[N][K],dis[N][K];
inline void clear(int u){
int pp=son[u].size();
for (int i=0;i<pp;i++){
int v=son[u][i]; flag[v]=clk;
if (*fat[v]!=1) sf[v].Clear(); sr[v].Clear(); cnt[v]=0;
while (fat[v][*fat[v]]!=u) --*fat[v],--*dis[v]; --*fat[v],--*dis[v];
if (v!=u) son[v].clear();
}
son[u].clear();
}
inline void dfs(int u,int fa,int d){
cnt[cur]++; size[u]=1; son[cur].push_back(u);
fat[u][++*fat[u]]=cur; dis[u][++*dis[u]]=d;
sr[cur].Insert(d-val[u]);
if (*fat[u]!=1) sf[cur].Insert(dis[u][*dis[u]-1]-val[u]);
for (int p=head[u];p;p=G[p].next)
if (flag[V]==clk && del[V]!=clk && V!=fa)
dfs(V,u,d+G[p].w),size[u]+=size[V];
}
inline void Divide(int u){
del[u]=clk; cur=u; dfs(u,0,0);
for (int p=head[u];p;p=G[p].next)
if (del[V]!=clk && flag[V]==clk){
sum=size[V]; minv=1<<30;
Root(V,0);
Divide(root);
}
}
inline ll Query(int u){
ll ans=0;
for (int i=*dis[u]-1;i;i--){
int d=dis[u][i],f=fat[u][i];
ans+=sr[f].Query(val[u]-d);
ans-=sf[fat[u][i+1]].Query(val[u]-d);
}
return ans;
}
const double cd=0.75;
int main(){
ll lastans=0; int a,b,c; const int P=1e9;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n); read(n);
SGT::Init();
for (int i=1;i<=n;i++) sr[i].Init(),sf[i].Init();
read(a); read(b); read(val[1]);
cnt[1]=1; son[1].push_back(1);
sr[1].Insert(0-val[1]); fat[1][++*fat[1]]=1; dis[1][++*dis[1]]=0;
write(lastans=0);
for (int i=2;i<=n;i++){
clk=i;
read(a); read(b); read(val[i]);
a=a^(lastans%P);
add(a,i,b,++inum); add(i,a,b,++inum);
for (int j=1;j<=*dis[a];j++) fat[i][++*fat[i]]=fat[a][j],dis[i][++*dis[i]]=dis[a][j]+b;
fat[i][++*fat[i]]=i; dis[i][++*dis[i]]=0;
for (int j=*dis[i];j;j--){
cnt[fat[i][j]]++; son[fat[i][j]].push_back(i);
sr[fat[i][j]].Insert(dis[i][j]-val[i]);
if (j!=*dis[i])
sf[fat[i][j+1]].Insert(dis[i][j]-val[i]);
}
write(lastans+=Query(i));
int pp=son[2].size();
int t=0;
for (int j=*dis[i];j>1;j--)
if (cnt[fat[i][j]]>cd*cnt[fat[i][j-1]]+5)
t=fat[i][j-1];
if (t){
int tmp=cnt[t];
clear(t);
sum=tmp; minv=1<<30; Root(t,0);
Divide(root);
}
}
return 0;
}