1. 程式人生 > 實用技巧 >loj6145. 「2017 山東三輪集訓 Day7」Easy

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;
}