suxxsfe

一言(ヒトコト)

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
  • 查询的时候大 vectorupper_bound,小 vector 上暴力查询

其实没多难写(

#define N 100006
#define M 200006
#define LOG_N 17
int n;
struct SqrtRebuild{
#define B 300 
	std::vector<int>v,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<s1&&j<s2){
				if(v[i]<added[j]) tmp[i+j]=v[i],i++;
				else tmp[i+j]=added[j],j++;
			}
			while(i<s1) tmp[i+j]=v[i],i++;
			while(j<s2) tmp[i+j]=added[j],j++;
			std::swap(v,tmp);
			std::vector<int>().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<int>().swap(v);std::vector<int>().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]) lib::swap(u,v);
		for(int j=LOG_N;~j;j--)if(deep[fa[j][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]<maxson[root]) root=u;
	}
	void divide(int u,int tot){
		allow[u]=0;
		for(int v,i=fir[u];i;i=nex[i]){
			v=to[i];
			if(!allow[v]) continue;
			size[0]=size[v]>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::vector<int>son[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<int>().swap(son[v]),T[v].clear(),Tfa[v].clear(),G.allow[v]=1,fa[v]=0,tmp[++tmp[0]]=v;
	std::vector<int>().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;
}
posted @ 2022-02-23 15:29  suxxsfe  阅读(27)  评论(0编辑  收藏  举报