P3920 [WC2014]紫荆花之恋
https://www.luogu.com.cn/problem/P3920
设 \(l\) 是 \((i,j)\) 路径上一点,则有:
\[dis(i,j)\le r_i+r_j \Rightarrow dis(i,l)+dis(j,l)\le r_i+r_j\Rightarrow dis(i,l)-r_i\le r_j-dis(j,l) \]当插入一个新的 \(j\) 时,就拿着 \(k=r_j-dis(j,l)\) 去每个 \(l\) 找有多少 \(i\) 满足 \(dis(i,l)-r_i\le k\)
那自然就是放到点分树上,用平衡树维护,每次查询排名,查完把 \(dis(j,l)-r_j\) 插入到每个点的平衡树上,当然每个点实际上是两个平衡树,因为还要容斥,不过这和别的题都差不多
如何处理动态插入?用类似替罪羊树的方法,每次插入时如果某点的最大子树(点分树上的)大小超过他本身大小的 \(\alpha\) 倍,就重构整个子树
为了方便可以给每个点维护一个 vector
存他所有的后代(点分树上),重构时就清空所有后代的平衡树,而这些后代在原树上一定是形成了一个连通块,标记下来在上面正常建点分树就行了
然后对于每个后代,跳链修改他们所有祖先的平衡树
由于单次重构是 \(O(n\log^2 n)\) 的不同于替罪羊树的 \(O(n)\),所以这个 \(\alpha\) 要取得大一些,大概 \(0.8\) 左右
然后发现平衡树跑得又慢码量又大,清空树的时候还要手动回收空间,可以用 vector
根号重构来替代
- 维护一个小
vector
一个大vector
,插入的时候往小vector
里插入,如果大小超过了根号就归并进保持元素有序的大vector
- 查询的时候大
vector
上upper_bound
,小vector
上暴力查询
其实没多难写(
#define N 100006
#define M 200006
#define LOG_N 17
int n;
struct SqrtRebuild{
#define B 300
std::vectorv,added,tmp;
inline void insert(int x){added.push_back(x);}
inline int rank(int x){
if(added.size()>B){
std::sort(added.begin(),added.end());
int i=0,j=0,s1=v.size(),s2=added.size();
tmp.resize(s1+s2);
while(i().swap(added);
}
int ans=std::upper_bound(v.begin(),v.end(),x)-v.begin();
for(int i:added) ans+=i<=x;
return ans;
}
inline void clear(){std::vector().swap(v);std::vector().swap(added);}
inline unsigned int size(){return v.size()+added.size();}
#undef B
}T[N],Tfa[N];
int fa[N],val[N];
struct Graph{
int fir[N],nex[M],to[M],tot;
int fa[19][N],deep[N],sum[N];
inline void add(int u,int v,int w){//u(fa) -> v(son)
to[++tot]=v;nex[tot]=fir[u];fir[u]=tot;to[++tot]=u;nex[tot]=fir[v];fir[v]=tot;
deep[v]=deep[u]+1;sum[v]=sum[u]+w;fa[0][v]=u;
for(int j=1;j<=LOG_N;j++) fa[j][v]=fa[j-1][fa[j-1][v]];
}
inline int getLca(int u,int v){
if(deep[u]=deep[v]) u=fa[j][u];
if(u==v) return u;
for(int j=LOG_N;~j;j--)if(fa[j][u]^fa[j][v]) u=fa[j][u],v=fa[j][v];
return fa[0][u];
}
inline int getDis(int u,int v){return sum[u]+sum[v]-(sum[getLca(u,v)]<<1);}
int allow[N],size[N],maxson[N],root;
void findRoot(int u,int fa=0){
size[u]=1;maxson[u]=0;
for(int v,i=fir[u];i;i=nex[i]){
v=to[i];
if(!allow[v]||v==fa) continue;
findRoot(v,u);size[u]+=size[v];
lib::chkMax(maxson[u],size[v]);
}
lib::chkMax(maxson[u],size[0]-size[u]);
if(maxson[u]size[u]?(tot-size[u]):size[u];root=0;maxson[0]=_INT_INF;
findRoot(v);::fa[root]=u;divide(root,size[v]);
}
}
}G;
#define alpha 0.8
std::vectorson[N];
inline void change(int u,int top){
for(int i=u;i^top;i=fa[i]) T[i].insert(G.getDis(u,i)-val[u]),fa[i]?Tfa[i].insert(G.getDis(u,fa[i])-val[u]):void(),son[i].push_back(u);
}
void rebuild(int u){
static int tmp[N];tmp[0]=0;
for(int v:son[u])if(v^u) std::vector().swap(son[v]),T[v].clear(),Tfa[v].clear(),G.allow[v]=1,fa[v]=0,tmp[++tmp[0]]=v;
std::vector().swap(son[u]);T[u].clear();Tfa[u].clear();G.allow[u]=1;tmp[++tmp[0]]=u;
int fau=fa[u];fa[u]=0;
G.size[0]=tmp[0];G.root=0;G.maxson[0]=_INT_INF;
G.findRoot(u);fa[G.root]=fau;G.divide(G.root,G.size[u]);
for(int i=1;i<=tmp[0];i++) change(tmp[i],fau);
}
void insert(int u,int f){
fa[u]=f;change(u,0);
int badtag=0;
for(int i=u;fa[i];i=fa[i]){
if(son[i].size()>son[fa[i]].size()*alpha+5) badtag=fa[i];
i=fa[i];
}
if(badtag) rebuild(badtag);
}
#undef alpha
long long ans;
inline void ask(int u,int k){
for(int last=0,dis,i=u;i;i=fa[i]){
dis=G.getDis(u,i);
ans+=T[i].rank(k-dis);
if(last) ans-=Tfa[last].rank(k-dis);
last=i;
}
}
int main(){
read();n=read();
read();read();val[1]=read();
G.deep[1]=1;insert(1,0);write("0\n");
#define MOD 1000000000
for(int fa,w,i=2;i<=n;i++){
fa=read()^(ans%MOD);w=read();val[i]=read();
G.add(fa,i,w);
ask(fa,val[i]-w);insert(i,fa);
writeEN(ans);
}
return RET;
}