标签:os io for amp size ad ios ef
给一颗无向树有n个结点,有m个询问,问树上任意两点间距离,n的范围是40000,m是200
这题告诉我们一个求树上两点间距离的好方法,就是先求根到其余所有点的距离,再求出询问的LCA,答案为dis[a]+dis[b]-2*dis[lca(a,b)]
#include <iostream> #include <cstdlib> #include <cstring> #include <string> #include <cstdio> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <map> #define inf 0x3f3f3f3f #pragma comment(linker, "/STACK:16777216") #define eps 1e-6 #define ll long long using namespace std; const int maxn=40010; int dis[maxn]; struct node { int v,id,w;//id为边号或询问号 node* next; }ed[maxn<<2],*head[maxn],*q[maxn]; struct qnode { int u,v,ans;//存询问结点,ans最近公共祖先 } qu[maxn]; int fa[maxn],vis[maxn],cnt; void init(int n) { cnt=0; memset(vis,0,sizeof vis); memset(head,0,sizeof head); memset(q,0,sizeof q); for(int i=0;i<=n;i++) fa[i]=i; } int getfa(int x) { if(fa[x]==x) return x; return fa[x]=getfa(fa[x]); } void LCA(int u) { fa[u]=u,vis[u]=1; for(node *p=q[u];p!=NULL;p=p->next) { if(vis[p->v]) { int id=p->id; qu[id].ans=getfa(p->v); } } for(node *p=head[u];p!=NULL;p=p->next) { if(!vis[p->v]) { LCA(p->v); fa[p->v]=u; } } } void adde(node *e[],int u,int v,int w,int id)//建边e传头节点数组。为询问边的或树边的。 { ed[cnt].v=v; ed[cnt].w=w; ed[cnt].id=id; ed[cnt].next=e[u]; e[u]=&ed[cnt++]; } void dfs(int s,int d) { for(node *p=head[s];p!=NULL;p=p->next) { if(!vis[p->v]) { vis[p->v]=1; dis[p->v]=d+(p->w); dfs(p->v,dis[p->v]); } } } int main() { int icy,a,b,c,i,m,n; scanf("%d",&icy); while(icy--) { scanf("%d%d",&n,&m); init(n); for(i=1;i<=n-1;i++) { scanf("%d%d%d",&a,&b,&c); adde(head,a,b,c,i); adde(head,b,a,c,i); } for(i=1;i<=m;i++) { scanf("%d%d",&a,&b); adde(q,a,b,0,i); adde(q,b,a,0,i); qu[i].u=a; qu[i].v=b; } LCA(1); memset(dis,0,sizeof dis); memset(vis,0,sizeof vis); vis[1]=1;dis[1]=0; dfs(1,0); for(i=1;i<=m;i++) printf("%d\n",dis[qu[i].u]+dis[qu[i].v]-dis[qu[i].ans]-dis[qu[i].ans]); } return 0; }
标签:os io for amp size ad ios ef
原文地址:http://blog.csdn.net/u011032846/article/details/38495227