loj6145. 「2017 山东三轮集训 Day7」Easy

题面

题解:由于区间内每个点和\(x\)的lca都不尽相同,我们很难用\(dep_x+dep_y-2\times dep_{lca}\)来进行求解。于是考虑点分治,把询问离线下来,挂在点\(x\)上。

发现问题变得很简单:我们只需要扫一遍分治中心的所有儿子,先在线段树上查一下区间离它最远的点的距离,然后再把自己加进线段树里就行了,注意正反要各做一遍。由于每个点只会涉及到log次线段树的单点修改、区间查询,时间复杂度就是\(O(nlog^2n)\)

如果本题强制在线,那么只需要把所有分治中心的线段树(或者平衡树)都建出来,然后在点分树上跳father,注意查的时候要减去它所在子树在线段树上的贡献就行了,这个东西对于做过动态点分治的大神们应该不陌生。

时间复杂度:\(O(nlog^2n)\)

代码:

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline int
#define C(x,y) memset(x,y,sizeof(x))
#define STS system("pause")
template<class D>I read(D &res){
	res=0;register D g=1;register char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-')g=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		res=(res<<3)+(res<<1)+(ch^48);
		ch=getchar();
	}
	res*=g;
}
const int INF=1e9+7;
struct E{
	int to,nt,w;
}e[202000];
struct P{
	int x,y,id;
	P(int _x=0,int _y=0,int _id=0){x=_x;y=_y;id=_id;}
};
#define T e[k].to
int n,m,rot,head[101000],tot,vis[101000],siz[101000],mx[101000],N,maxi,root,ans[101000];
vector<int>G[101000],tmp;
vector<P>t[101000];
struct Segtree{
	int tr[404000],laz[404000];
	#define all 1,1,n
	#define lt k<<1,l,mid
	#define rt k<<1|1,mid+1,r
	I add(int k){tr[k]=INF;laz[k]=1;}
	I push_down(int k){
		add(k<<1),add(k<<1|1);laz[k]=0;
	}
	I modi(int k,int l,int r,int x,int w){
		if(l==r)return tr[k]=w,void();
		if(laz[k])push_down(k);
		re mid=(l+r)>>1;
		if(x<=mid)modi(lt,x,w);
		else modi(rt,x,w);
		tr[k]=min(tr[k<<1],tr[k<<1|1]);
	}
	IN ques(int k,int l,int r,int x,int y){
		if(x>r||y<l)return INF;
		if(x<=l&&r<=y)return tr[k];
		if(laz[k])push_down(k);
		re mid=(l+r)>>1;
		return min(ques(lt,x,y),ques(rt,x,y));
	}
}S;
I add(int x,int y,int w){
	e[++tot].to=y;e[tot].nt=head[x];head[x]=tot;e[tot].w=w;
}
I findroot(int x,int fa){
	siz[x]=1;mx[x]=0;
	for(re k=head[x];k!=-1;k=e[k].nt){
		if(T==fa||vis[T])continue;
		findroot(T,x);mx[x]=max(mx[x],siz[T]);
		siz[x]+=siz[T];
	}
	mx[x]=max(mx[x],N-siz[x]);
	if(mx[x]<maxi)maxi=mx[x],root=x;
}
I D_1(int x,int fa){
	siz[x]=1;
	for(re k=head[x];k!=-1;k=e[k].nt){
		if(T==fa||vis[T])continue;
		D_1(T,x);siz[x]+=siz[T];
	}
}
I divided(int x,int fa){
	if(fa)G[fa].emplace_back(x);
	D_1(x,0);vis[x]=1;
	for(re k=head[x];k!=-1;k=e[k].nt){
		if(T==fa||vis[T])continue;
		N=siz[T];maxi=INF;
		findroot(T,x);divided(root,x);
	}
}
I D_2(int x,int fa,int dist){
	for(auto d:t[x])ans[d.id]=min(ans[d.id],S.ques(all,d.x,d.y)+dist);
	for(re k=head[x];k!=-1;k=e[k].nt){
		if(T==fa||vis[T])continue;
		D_2(T,x,dist+e[k].w);
	}
}
I D_3(int x,int fa,int dist){
	S.modi(all,x,dist);
	for(re k=head[x];k!=-1;k=e[k].nt){
		if(T==fa||vis[T])continue;
		D_3(T,x,dist+e[k].w);
	}
}
I solve(int x){
	S.add(1);S.modi(all,x,0);tmp.clear();
	for(re k=head[x];k!=-1;k=e[k].nt){
		if(vis[T])continue;
		tmp.emplace_back(k);
		D_2(T,x,e[k].w);D_3(T,x,e[k].w);
	}
	reverse(tmp.begin(),tmp.end());
	S.add(1);S.modi(all,x,0);
	for(auto k:tmp)D_2(T,x,e[k].w),D_3(T,x,e[k].w);
	for(auto d:t[x])ans[d.id]=min(ans[d.id],S.ques(all,d.x,d.y));
	vis[x]=1;
	for(auto d:G[x])solve(d);
}
int main(){
	read(n);C(head,-1);tot=-1;
	re X,Y,W;
	F(i,1,n-1){
		read(X);read(Y);read(W);
		add(X,Y,W);add(Y,X,W);
	}
	N=n;maxi=INF;findroot(1,0);rot=root;divided(root,0);
	read(m);
	F(i,1,m){
		read(X);read(Y);read(W);
		t[W].emplace_back(P(X,Y,i));ans[i]=INF;
	}
	C(vis,0);solve(rot);
	F(i,1,m)printf("%d\n",ans[i]);
	return 0;
}
posted @ 2020-07-20 21:36  Purple_wzy  阅读(130)  评论(0编辑  收藏  举报