HDU 2586(LCA欧拉序和st表)

什么是欧拉序,可以去这个大佬的博客(https://www.cnblogs.com/stxy-ferryman/p/7741970.html)巨详细

因为欧拉序中的两点之间,就是两点遍历的过程,所以只要找遍历过程中对应的最小的深度就行了,这里用st表存,first存第一个u出现的地方,用value存欧拉序,同时用depth存对应深度

模板

 1 struct node{
 2     int v,next,dist;
 3 }a[maxn<<1];
 4 int n,m,tot,len;
 5 int st[maxn<<1][20], depth[maxn<<1],value[maxn<<1],first[maxn<<1];
 6 int dist[maxn],head[maxn];
 7 void add(int u,int v,int dist0){
 8     a[tot].next=head[u];
 9     a[tot].dist=dist0;
10     a[tot].v=v;
11     head[u]=tot++;
12 }
13 void dfs(int u,int fa,int d) {
14     value[++len]=u;depth[len]=d;first[u]=len;
15     for (int i=head[u];~i;i=a[i].next){
16         int v=a[i].v;if(v==fa)continue;
17         dist[v]=dist[u]+a[i].dist;
18         dfs(v,u,d+1);
19         value[++len]=u;depth[len]=d;
20     }
21 }
22 inline void init(int n){
23     for(int i=0;i<=n;i++)head[i]=-1,depth[i]=0;
24     tot=0,len=0;
25 }
26 inline void makest(){
27     for(it i=1;i<=len;i++)st[i][0]=depth[i];
28     for(it i=1;1<<i<=len;i++){
29         for(it j=1;j+(1<<i)-1<=len;j++){
30             st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
31         }
32     }
33 }
34 inline int dis(int u,int v){
35     int l=first[u],r=first[v];
36     if(l>r){swap(l,r);}
37     int k=log2(r-l+1);
38     int dep=min(st[l][k],st[r-(1<<k)+1][k]);
39     return dist[u]+dist[v]-2*dist[value[first[dep]]];
40 }

题意:

以1为根的树,两个点之间的最近距离是多少

思路:

模板LCA

用欧拉序+st表

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define il inline
 5 #define it register int
 6 #define inf 0x3f3f3f3f
 7 #define lowbit(x) (x)&(-x)
 8 #define mem(a,b) memset(a,b,sizeof(a))
 9 #define modd 998244353
10 const int maxn=4e4+10;
11 struct node{
12     int v,next,dist;
13 }a[maxn<<1];
14 int n,m,tot,len;
15 int st[maxn<<1][20], depth[maxn<<1],value[maxn<<1],first[maxn<<1];
16 int dist[maxn],head[maxn];
17 void add(int u,int v,int dist0){
18     a[tot].next=head[u];
19     a[tot].dist=dist0;
20     a[tot].v=v;
21     head[u]=tot++;
22 }
23 void dfs(int u,int fa,int d) {
24     value[++len]=u;depth[len]=d;first[u]=len;
25     for (int i=head[u];~i;i=a[i].next){
26         int v=a[i].v;if(v==fa)continue;
27         dist[v]=dist[u]+a[i].dist;
28         dfs(v,u,d+1);
29         value[++len]=u;depth[len]=d;
30     }
31 }
32 inline void init(int n){
33     for(int i=0;i<=n;i++)head[i]=-1,depth[i]=0;
34     tot=0,len=0;
35 }
36 inline void makest(){
37     for(it i=1;i<=len;i++)st[i][0]=depth[i];
38     for(it i=1;1<<i<=len;i++){
39         for(it j=1;j+(1<<i)-1<=len;j++){
40             st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
41         }
42     }
43 }
44 inline int dis(int u,int v){
45     int l=first[u],r=first[v];
46     if(l>r){swap(l,r);}
47     int k=log2(r-l+1);
48     int dep=min(st[l][k],st[r-(1<<k)+1][k]);
49     return dist[u]+dist[v]-2*dist[value[first[dep]]];
50 }
51 int main(){
52     int t;
53     scanf("%d",&t);
54     while(t--){
55         scanf("%d%d",&n,&m);
56         init(n);
57         for(it i=0;i<n-1;i++){int u,v,w;
58             scanf("%d%d%d",&u,&v,&w);
59             add(u,v,w);add(v,u,w);
60         }
61         dfs(1,0,1);
62         makest();
63         while(m--){
64             int l,r;
65             scanf("%d%d",&l,&r);
66             printf("%d\n",dis(l,r));
67         }
68     }
69     return 0;
70 }

用倍增

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define il inline
 5 #define it register int
 6 #define inf 0x3f3f3f3f
 7 #define lowbit(x) (x)&(-x)
 8 #define mem(a,b) memset(a,b,sizeof(a))
 9 #define modd 998244353
10 const int maxn=4e4+10;
11 struct node{
12     int v,next,dist;
13 }a[maxn<<1];
14 int n,m,tot;
15 int fath[maxn][20], depth[maxn];
16 int dist[maxn],head[maxn];
17 void add(int u,int v,int dist0){
18     a[tot].next=head[u];
19     a[tot].dist=dist0;
20     a[tot].v=v;
21     head[u]=tot++;
22 }
23 void dfs(int u,int fa,int d) {
24     fath[u][0]=fa; depth[u]=d;
25     for(int i=1;i<20;i++) fath[u][i]=fath[fath[u][i-1]][i-1];
26     for (int i=head[u];~i;i=a[i].next){
27         int v=a[i].v;if(v==fa)continue;
28         dist[v]=dist[u]+a[i].dist;
29         dfs(v,u,d+1);
30     }
31 }
32 void init(int n){
33     for(int i=0;i<=n;i++)fath[i][0]=0,dist[i]=0,head[i]=-1,depth[i]=0;
34     tot=0;
35 }
36 inline int lca(int x,int y){
37     if(depth[x]<depth[y])swap(x,y);
38     int h=depth[x]-depth[y];
39     for(it i=0;h>0;i++){
40         if(h&1){
41             x=fath[x][i];
42         }
43         h>>=1;
44     }
45     if(x==y)return x;
46     for(it i=19;i>=0;i--){
47         if(fath[x][i]!=fath[y][i]){
48             x=fath[x][i];
49             y=fath[y][i];
50         }
51     }
52     return fath[x][0];
53 }
54 inline int dis(int u,int v){
55     int d=lca(u,v);
56     return dist[u]+dist[v]-2*dist[d];
57 }
58 int main(){
59     int t;
60     scanf("%d",&t);
61     while(t--){
62         scanf("%d%d",&n,&m);
63         init(n);
64         for(it i=0;i<n-1;i++){int u,v,w;
65             scanf("%d%d%d",&u,&v,&w);
66             add(u,v,w);add(v,u,w);
67         }
68         dfs(1,0,1);
69         while(m--){
70             int l,r;
71             scanf("%d%d",&l,&r);
72             printf("%d\n",dis(l,r));
73         }
74     }
75     return 0;
76 }

原文地址:https://www.cnblogs.com/luoyugongxi/p/12347268.html

时间: 2024-08-29 09:46:21

HDU 2586(LCA欧拉序和st表)的相关文章

lca 欧拉序+rmq(st) 欧拉序+rmq(线段树) 离线dfs

https://www.luogu.org/problemnew/show/P3379 1.欧拉序+rmq(st) 1 /* 2 在这里,对于一个数,选择最左边的 3 选择任意一个都可以,[left_index,right_index],深度都大于等于这个数的深度 4 */ 5 #include <cstdio> 6 #include <cstdlib> 7 #include <cmath> 8 #include <cstring> 9 #include &

HDU 4836 The Query on the Tree lca || 欧拉序列 || 动态树

lca的做法还是很明显的,简单粗暴, 不过不是正解,如果树是长链就会跪,直接变成O(n).. 最后跑的也挺快,出题人还是挺阳光的.. 动态树的解法也是听别人说能ac的,估计就是放在splay上剖分一下,做法还是比较复杂的,,, 来一发lca: #include <stdio.h> #include <iostream> #include <algorithm> #include <sstream> #include <stdlib.h> #inc

P3379 【模板】最近公共祖先(LCA)(欧拉序+rmq)

P3379 [模板]最近公共祖先(LCA) 用欧拉序$+rmq$维护的$lca$可以做到$O(nlogn)$预处理,$O(1)$查询 从这里剻个图 #include<iostream> #include<cstdio> #include<vector> using namespace std; int read(){ char c=getchar(); int x=0; while(c<'0'||c>'9') c=getchar(); while('0'&l

欧拉序动态维护树直径

https://zhuanlan.zhihu.com/p/84236967 https://www.cnblogs.com/TinyWong/p/11260601.html 一个月过去了,我还是没有学动态点分治... 欧拉序保存了每个节点进入和返回的情况,$n$ 个结点的树,欧拉序列长度为 $2n - 1$. 两个结点的LCA就是它们在欧拉序中出现的位置的区间中,深度最小的那个结点. 对于边权为正的树,上面定义中的深度也可以换成到根的距离,用dis[u]表示结点 $u$ 到根的距离. 那么两个节

【BZOJ 3772】精神污染 主席树+欧拉序

这道题的内存-------真·精神污染---.. 这道题的思路很明了,我们就是要找每一个路径包含了多少其他路径那么就是找,有多少路径的左右端点都在这条路径上,对于每一条路径,我们随便选定一个端点作为第一关键字,另一个作为第二关键字,于是就有了两维限制,按照主席树的一般思路,我们把建树顺序作为一维,然后在里面维护另一维,那么我们在外面限制第一关键字,就是在树上建主席树,查询减LCA,在里面的话我们把每个点作为第一关键字对应的第二关键字,放入主席树,而主席树维护的是欧拉序区间,所以我们每次查询只用查

HDU 1695 GCD 欧拉函数+容斥原理+质因数分解

链接:http://acm.hdu.edu.cn/showproblem.php?pid=1695 题意:在[a,b]中的x,在[c,d]中的y,求x与y的最大公约数为k的组合有多少.(a=1, a <= b <= 100000, c=1, c <= d <= 100000, 0 <= k <= 100000) 思路:因为x与y的最大公约数为k,所以xx=x/k与yy=y/k一定互质.要从a/k和b/k之中选择互质的数,枚举1~b/k,当选择的yy小于等于a/k时,可以

hdu 2586 LCA模板题(离线算法)

http://acm.hdu.edu.cn/showproblem.php?pid=2586 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&quo

HDU 2588 GCD (欧拉函数)

GCD Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1013    Accepted Submission(s): 457 Problem Description The greatest common divisor GCD(a,b) of two positive integers a and b,sometimes writt

Underground Lab CodeForces - 782E (欧拉序)

大意:$n$结点,$m$条边无向图, 有$k$个人, 每个人最多走$\left\lceil\frac {2n}{k}\right\rceil$步, 求一种方案使得$k$个人走遍所有的点 $n$结点树的欧拉序长度为$2n-1$, 直接取$dfs$树的欧拉序即可 #include <iostream> #include <algorithm> #include <math.h> #include <cstdio> #include <vector>