HDU 2586.How far away ?-在线LCA(ST)-代码很认真的写了注释(捞到变形)
2018.9.10 0:40 重新敲一遍,然后很认真的写了注释,方便自己和队友看,刚过去的一天的下午打网络赛有一题用到了这个,但是没写注释,队友改板子有点伤,因为我没注释。。。
以后写博客,代码要写注释,要把题目意思写上。。。
我好捞啊。。。
How far away ?
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 21408 Accepted Submission(s): 8432
Problem Description
There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to house B"? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path("simple" means you can't visit a place twice) between every two houses. Yout task is to answer all these curious people.
Input
First line is a single integer T(T<=10), indicating the number of test cases.
For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n.
Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.
For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n.
Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.
Output
For each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.
Sample Input
2
3 2
1 2 10
3 1 15
1 2
2 3
2 2
1 2 100
1 2
2 1
Sample Output
10
25
100
100
Source
这个题就是求两点之间的最短距离,就是LCA模板题
代码:
1 //HDU2586 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<bitset> 7 #include<cassert> 8 #include<cctype> 9 #include<cmath> 10 #include<cstdlib> 11 #include<ctime> 12 #include<deque> 13 #include<iomanip> 14 #include<list> 15 #include<map> 16 #include<queue> 17 #include<set> 18 #include<stack> 19 #include<vector> 20 using namespace std; 21 typedef long long ll; 22 23 const double PI=acos(-1.0); 24 const double eps=1e-6; 25 const ll mod=1e9+7; 26 const int inf=0x3f3f3f3f; 27 const int maxn=4e4+10; 28 const int maxm=100+10; 29 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 30 31 int dp[maxn<<1][25];//数组记得开2倍,因为遍历之后序列长度变为2*n-1 32 bool vis[maxn];//标记 33 34 struct node{ 35 int u,v,w,next; 36 }edge[maxn<<1]; 37 38 int tot,head[maxn];//head保存的是以当前节点为起点的所有边中最后一条边的编号 39 40 int num; 41 42 inline void add(int u,int v,int w) 43 { 44 edge[num].u=u;edge[num].v=v;edge[num].w=w;//存边和权值 45 edge[num].next=head[u];head[u]=num++;//next保存的是以u为起点的上一条边的编号 46 u=u^v;v=u^v;u=u^v;//节点互换,存两次,因为为无向图,(u,v)存一次,(v,u)存一次,以下操作同上 47 edge[num].u=u;edge[num].v=v;edge[num].w=w; 48 edge[num].next=head[u];head[u]=num++; 49 } 50 51 int ver[maxn<<1],deep[maxn<<1],node[maxn<<1],dir[maxn<<1]; 52 //ver节点编号,dfs搜索过程中的序列,deep深度,node点编号位置,dir距离 53 54 void dfs(int u,int dep) 55 { 56 vis[u]=true;//标记u节点被访问过 57 ver[++tot]=u;//存dfs序 58 node[u]=tot;//节点的dfs序的编号 59 deep[tot]=dep;//该编号的深度 60 for(int k=head[u];k!=-1;k=edge[k].next)//倒着遍历以u节点为起点的所有边的编号 61 if(!vis[edge[k].v]){//如果该编号的边未被访问过 62 int v=edge[k].v,w=edge[k].w;//v表示该边的终点,w表示该边的权值 63 dir[v]=dir[u]+w;//权值和 64 dfs(v,dep+1);//再往下dfsv节点的深度 65 ver[++tot]=u;deep[tot]=dep;//表示dfs的时候还要回溯到上面,就是把dfs序保存一下,走到底再返回去去遍历没走过的点 66 } 67 } 68 //可以看以前写的RMQ(ST)的详解https://www.cnblogs.com/ZERO-/p/8456910.html 69 void ST(int n)//ST操作 70 { 71 for(int i=1;i<=n;i++) 72 dp[i][0]=i;//初始化为自己 73 for(int j=1;(1<<j)<=n;j++){ 74 for(int i=1;i+(1<<j)-1<=n;i++){ 75 int a=dp[i][j-1],b=dp[i+(1<<(j-1))][j-1]; 76 dp[i][j]=deep[a]<deep[b]?a:b; 77 } 78 } 79 } 80 81 int RMQ(int l,int r) 82 { 83 int k=0; 84 while((1<<(k+1))<=r-l+1)k++;//最多能跳2的多少次幂 85 int a=dp[l][k],b=dp[r-(1<<k)+1][k];//保存的是编号 86 return deep[a]<deep[b]?a:b; 87 } 88 89 int LCA(int u,int v) 90 { 91 int x=node[u],y=node[v]; 92 if(x>y)swap(x,y); 93 int res=RMQ(x,y); 94 return ver[res]; 95 } 96 97 int main() 98 { 99 int cas; 100 scanf("%d",&cas); 101 while(cas--){ 102 int n,q; 103 num=0; 104 scanf("%d%d",&n,&q); 105 memset(head,-1,sizeof(head));//初始化 106 memset(vis,false,sizeof(vis)); 107 for(int i=1;i<n;i++){ 108 int u,v,w; 109 scanf("%d%d%d",&u,&v,&w); 110 add(u,v,w);//存边 111 } 112 tot=0;dir[1]=0; 113 dfs(1,1); 114 ST(2*n-1); 115 while(q--){ 116 int u,v; 117 scanf("%d%d",&u,&v); 118 int lca=LCA(u,v); 119 printf("%d\n",dir[u]+dir[v]-2*dir[lca]);//两点最短距离为每个点到根节点的距离-最近公共祖先到根节点的距离的*2 120 } 121 } 122 return 0; 123 }
就这样,捞咸鱼。。。
༼༎ຶᴗ༎ຶ༽