1、给定一棵树,每条边都有一定的权值,q次询问,每次询问某两点间的距离。
2、这样就可以用LCA来解,首先找到u, v 两点的lca,然后计算一下距离值就可以了。
这里的计算方法是,记下根结点到任意一点的距离dis[],这样ans = dis[u] + dis[v] - 2 * dis[lca(u, v)]
3、
/* 离线算法,LCATarjan 复杂度O(n+Q); */ #include<iostream> #include<stdio.h> #include<string.h> using namespace std; const int MAXN=40005; const int MAXQ=205;//查询数的最大值 int dis[MAXN];//到根节点的距离 //并查集部分 int F[MAXN];//需要初始化为-1 int find(int x){ if(F[x]==-1)return x; return F[x]=find(F[x]); } void bing(int u,int v){ int t1=find(u); int t2=find(v); if(t1!=t2) F[t1]=t2; } //*********************** bool vis[MAXN];//访问标记 int ancestor[MAXN];//祖先 struct Edge{ int to,next; int d; }edge[MAXN*2]; int head[MAXN],tot; void addedge(int u,int v,int d){ edge[tot].to=v; edge[tot].d=d; edge[tot].next=head[u]; head[u]=tot++; } struct Query{ int q,next; int index;//查询编号 }query[MAXQ*2]; int answer[MAXQ];//存储最后的查询结果,下标0 Q-1 int h[MAXN];//注意此处为MAXN... int tt; void add_query(int u,int v,int index){ query[tt].q=v; query[tt].next=h[u]; query[tt].index=index; h[u]=tt++; query[tt].q=u; query[tt].next=h[v]; query[tt].index=index; h[v]=tt++; } void init(){ tot=0; memset(head,-1,sizeof(head)); tt=0; memset(h,-1,sizeof(h)); memset(vis,false,sizeof(vis)); memset(F,-1,sizeof(F)); memset(ancestor,0,sizeof(ancestor)); } void LCA(int u){ ancestor[u]=u; vis[u]=true; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].to; if(vis[v])continue; dis[v]=dis[u]+edge[i].d; LCA(v); bing(u,v); ancestor[find(u)]=u; } for(int i=h[u];i!=-1;i=query[i].next){ int v=query[i].q; if(vis[v]){ answer[query[i].index]=ancestor[find(v)]; } } } int main(){ int T; int n,m; int i; int u,v,d; scanf("%d",&T); while(T--){ init(); scanf("%d%d",&n,&m); for(i=0;i<n-1;++i){ scanf("%d%d%d",&u,&v,&d); addedge(u,v,d); addedge(v,u,d); } for(i=0;i<m;++i){ scanf("%d%d",&u,&v); add_query(u,v,i); } dis[1]=0; LCA(1); for(i=0;i<m;++i){ printf("%d\n",dis[query[i*2].q]+dis[query[i*2+1].q]-2*dis[answer[i]]); } } return 0; }
时间: 2024-10-22 15:10:58