标签:namespace hid scan -o oid from 公共祖先 ble const
时间限制: 1 s
小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上。有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花费太多精力。已知从某个节点爬到其父亲节点要花费 c 的能量(从父亲节点爬到此节点也相同),他们想找出一条花费精力最短的路,以使得搞基的时候精力旺盛,他们找到你要你设计一个程序来找到这条路,要求你告诉他们最少需要花费多少精力
输入描述 Input Description
第一行一个n,接下来n-1行每一行有三个整数u,v, c 。表示节点 u 爬到节点 v 需要花费 c 的精力。
第n+1行有一个整数m表示有m次询问。接下来m行每一行有两个整数 u ,v 表示两只虫子所在的节点。
一共有m行,每一行一个整数,表示对于该次询问所得出的最短距离。
3
1 0 1
2 0 1
3
1 0
2 0
1 2
1
1
2
数据范围及提示 Data Size & Hint
1<=n<=50000, 1<=m<=75000, 0<=c<=1000
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int maxn=50010; 5 struct point{int from,to,v;}e[maxn*2]; 6 int n,m,cnt,a,b,c; 7 int head[maxn],deep[maxn],x[maxn][17],di[maxn]; 8 //deep数组表示节点所在的层数,di数组表示节点到根节点的距离 9 //x[i][j]的含义为:节点i的祖先中与其相差2^j层的节点;例如,x[i][0]代表节点i的父亲 10 bool f[maxn];//判断节点是否访问过 11 void add(int a,int b,int c)//邻接表建边 12 {cnt++;e[cnt].from=head[a];e[cnt].to=b;e[cnt].v=c;head[a]=cnt;} 13 void dfs(int k) 14 { 15 f[k]=true; 16 for(int i=1;(1<<i)<=deep[k];i++) 17 x[k][i]=x[x[k][i-1]][i-1];//递推得出x数组 18 for(int i=head[k];i;i=e[i].from) 19 { 20 if(!f[e[i].to]) 21 { 22 x[e[i].to][0]=k;//将节点k标记为e[i].to的父亲 23 deep[e[i].to]=deep[k]+1;//层数+1 24 di[e[i].to]=di[k]+e[i].v; 25 dfs(e[i].to); 26 } 27 } 28 } 29 int solve(int ri,int rj) 30 { 31 if(deep[ri]<deep[rj])swap(ri,rj); 32 int d=deep[ri]-deep[rj]; 33 for(int i=0;(1<<i)<=d;i++)//利用倍增思想,将ri节点跳到与rj节点同层 34 if((1<<i)&d)ri=x[ri][i]; 35 if(ri==rj)return ri;//找到最近公共祖先 36 for(int i=16;i>=0;i--) 37 if((1<<i)<=deep[rj]&&x[ri][i]!=x[rj][i]) 38 ri=x[ri][i],rj=x[rj][i];//同时往上跳,直到ri与rj为兄弟节点为止 39 return x[ri][0];//返回他们的父亲 40 } 41 int main() 42 { 43 scanf("%d",&n); 44 for(int i=1;i<n;i++) 45 { 46 scanf("%d%d%d",&a,&b,&c); 47 add(a,b,c); 48 add(b,a,c); 49 } 50 dfs(0);//此处假设以0为根节点 51 scanf("%d",&m); 52 while(m--) 53 { 54 scanf("%d%d",&a,&b); 55 printf("%d\n",di[a]+di[b]-2*di[solve(a,b)]); 56 } 57 return 0; 58 }
标签:namespace hid scan -o oid from 公共祖先 ble const
原文地址:http://www.cnblogs.com/zsnuo/p/6786431.html