题意
给出一棵树,每次询问一个点
x
x
到编号在中的点的距离的最小值。
n,q≤105
n
,
q
≤
10
5
分析
先把点分树搞出来,然后对每个分治中心开一棵线段树来记录每个点到分治中心的距离最小值。
查询的话,就在该点在点分树上到根的路径中所有的线段树上查询即可。
为什么这样是对的呢?首先因为所有点都会被算到,其次,距离只会被我们算大,不会被算小。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define mp(x,y) std::make_pair(x,y)
typedef std::pair<int,int> pi;
const int N=100005;
const int inf=1000000000;
int n,cnt,last[N],root,sum,size[N],f[N],pre[N],rt[N],sz,tot;
struct edge{int to,next,w;}e[N*2];
struct tree{int l,r,mn;}t[N*100];
pi a[N];
bool vis[N];
int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void addedge(int u,int v,int w)
{
e[++cnt].to=v;e[cnt].w=w;e[cnt].next=last[u];last[u]=cnt;
e[++cnt].to=u;e[cnt].w=w;e[cnt].next=last[v];last[v]=cnt;
}
void ins(int &d,int l,int r,int x,int y)
{
if (!d) d=++sz;
if (l==r) {t[d].mn=y;return;}
int mid=(l+r)/2;
if (x<=mid) ins(t[d].l,l,mid,x,y);
else ins(t[d].r,mid+1,r,x,y);
t[d].mn=std::min(t[t[d].l].mn,t[t[d].r].mn);
}
int query(int d,int l,int r,int x,int y)
{
if (!d) return inf;
if (x<=l&&r<=y) {return t[d].mn;}
int mid=(l+r)/2,ans=inf;
if (x<=mid) ans=std::min(ans,query(t[d].l,l,mid,x,y));
if (y>mid) ans=std::min(ans,query(t[d].r,mid+1,r,x,y));
return ans;
}
void get_root(int x,int fa)
{
size[x]=1;f[x]=0;
for (int i=last[x];i;i=e[i].next)
{
if (e[i].to==fa||vis[e[i].to]) continue;
get_root(e[i].to,x);
size[x]+=size[e[i].to];
f[x]=std::max(f[x],size[e[i].to]);
}
f[x]=std::max(f[x],sum-size[x]);
if (!root||f[x]<f[root]) root=x;
}
void get(int x,int fa,int dep)
{
a[++tot]=mp(x,dep);size[x]=1;
for (int i=last[x];i;i=e[i].next)
if (e[i].to!=fa&&!vis[e[i].to]) get(e[i].to,x,dep+e[i].w),size[x]+=size[e[i].to];
}
void solve(int x)
{
vis[x]=1;
ins(rt[x],1,n,x,0);
for (int i=last[x];i;i=e[i].next)
{
if (vis[e[i].to]) continue;
tot=0;get(e[i].to,x,e[i].w);
for (int j=1;j<=tot;j++) ins(rt[x],1,n,a[j].first,a[j].second);
}
for (int i=last[x];i;i=e[i].next)
{
if (vis[e[i].to]) continue;
root=0;sum=size[e[i].to];get_root(e[i].to,x);
pre[root]=x;solve(root);
}
}
int main()
{
n=read();
for (int i=1;i<n;i++)
{
int x=read(),y=read(),z=read();
addedge(x,y,z);
}
t[0].mn=inf;
root=0;sum=n;get_root(1,0);
solve(root);
int q=read();
while (q--)
{
int l=read(),r=read(),x=read(),ans=inf,y=x;
while (y)
{
ans=std::min(ans,query(rt[y],1,n,l,r)+query(rt[y],1,n,x,x));
y=pre[y];
}
printf("%d\n",ans);
}
return 0;
}