51nod2621 树上距离一题四解ST表+倍增+Tarjan+树剖

LCA裸题 只有代码无原理,给自己复习用

1. ST表(这题2^10就够了)

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3
 4 const int maxn=2e3+50;
 5
 6 int cnt,dfn[maxn],dep[maxn],dp[maxn][21],lg2[maxn],dis[maxn],w[maxn][maxn];
 7 std::vector<int> G[maxn];
 8 void dfs(int u,int fa){
 9     dis[u]=dis[fa]+w[u][fa];
10     dfn[u]=++cnt; dep[u]=dep[fa]+1; dp[cnt][0]=u;
11     for(int i=0,v;i<G[u].size();i++){
12         if((v=G[u][i])==fa) continue;
13         dfs(v,u);
14         dp[++cnt][0]=u;
15     }
16 }
17 void st(){
18     for(int i=2;i<=cnt;i++) lg2[i]=lg2[i>>1]+1;
19     for(int j=1;j<=20;j++){
20         for(int i=1;i+(1<<j)-1<=cnt;i++){
21             int r=i+(1<<(j-1));
22             dp[i][j] = dep[dp[i][j - 1]] < dep[dp[r][j - 1]] ? dp[i][j - 1] : dp[r][j - 1];
23         }
24     }
25 }
26 int que(int l,int r){
27     if(l>r) swap(l,r);
28     int k=lg2[r-l+1];
29     return dep[dp[l][k]] < dep[dp[r - (1 << k) + 1][k]] ? dp[l][k] : dp[r - (1 << k) + 1][k];
30 }
31 int main(){
32     int n,q; cin>>n>>q;
33     for(int i=1;i<n;i++){
34         int u,v,we; cin>>u>>v>>we;
35         G[u].push_back(v);
36         G[v].push_back(u);
37         w[u][v]=w[v][u]=we;
38     }
39     dfs(1,0); st();
40     for(int i=0;i<q;i++){
41         int u,v; cin>>u>>v;
42         printf("%d\n",dis[u]+dis[v]-2*dis[que(dfn[u],dfn[v])]);
43     }
44     return 0;
45 }

2. 倍增

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3
 4 const int maxn=2e3+50;
 5 vector<int> G[maxn];
 6 int dep[maxn],fa[maxn][13],dis[maxn],w[maxn][maxn],lim=11;
 7 void dfs(int u,int rt){
 8     dep[u]=dep[rt]+1; fa[u][0]=rt; dis[u]=dis[rt]+w[rt][u];
 9     for(int i=1;i<lim;i++) fa[u][i]=fa[fa[u][i-1]][i-1];
10     for(int i=0;i<G[u].size();i++){
11         int v=G[u][i]; if(v!=rt) dfs(v,u);
12     }
13 }
14
15 int LCA(int x,int y){
16     if(dep[x]<dep[y]) swap(x,y);//x更深
17     for(int i=lim-1;~i;i--)//x上移
18         if(dep[x]-(1<<i)>=dep[y]) x=fa[x][i];
19     if(x==y) return x;
20     for(int i=lim-1;~i;i--)
21         if(fa[x][i]!=fa[y][i])
22             x=fa[x][i], y=fa[y][i];
23     return fa[x][0];
24 }
25 int main(){
26     ios::sync_with_stdio(0);
27     cin.tie(0); cout.tie(0);
28     int n,q; cin>>n>>q;
29     for(int i=1;i<n;i++){
30         int u,v,we; cin>>u>>v>>we;
31         G[u].push_back(v);
32         G[v].push_back(u);
33         w[u][v]=w[v][u]=we;
34     }
35     dfs(1,0);
36     for(int i=0;i<q;i++){
37         int u,v; cin>>u>>v;
38         int lca=LCA(u,v);
39         cout<<dis[u]+dis[v]-2*dis[lca]<<endl;
40     }
41
42     return 0;
43 }

3. tarjan

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3
 4 const int maxn=2e3+50;
 5 struct node{ int next,to; }edge[maxn];
 6 int head[maxn],cnt;
 7 void add(int u,int v){
 8     edge[++cnt].to = v;
 9     edge[cnt].next = head[u];
10     head[u] = cnt;
11 }
12
13 struct node2{ int id,to,next; }que[maxn];
14 int qhead[maxn],cnt2;
15 void add_q(int u,int v,int i){
16     que[++cnt2].to = v;
17     que[cnt2].id = i;
18     que[cnt2].next = qhead[u];
19     qhead[u] = cnt2;
20 }
21
22 int fa[maxn],lca[maxn],w[maxn][maxn],dis[maxn],ans[maxn];
23 bool vis[maxn];
24
25 int findd(int x){ return x==fa[x]?x:fa[x]=findd(fa[x]); }
26
27 void tarjan(int u){
28     vis[u] = 1;
29     for(int i = head[u];i;i = edge[i].next){
30         int v = edge[i].to; if(v==u) continue;
31         if(!vis[v]){                                        //如果没有被访问过,就tagjan这个点
32             dis[v]=dis[u]+w[u][v];
33             tarjan(v);
34             fa[v] =findd(u);
35         }
36     }
37     for(int i = qhead[u];i;i = que[i].next){
38         int v = que[i].to; if(v==u) continue;
39         if(vis[v]){                                          //找答案时,已经访问过的节点就可以记录lca了
40             lca[que[i].id] = findd(v);
41             ans[que[i].id]=dis[u]+dis[v]-2*dis[lca[que[i].id]];
42            }
43     }
44 }
45 int rt[maxn];
46 int main(){
47     int n,m; cin >> n >> m ;
48     int a,b,we;
49     for(int i = 1;i < n;i ++){
50         cin >> a >> b>>we;
51         add(a,b);
52         add(b,a);
53         w[a][b]=w[b][a]=we;
54     }
55     for(int i = 1;i <= m;i ++){
56         cin >> a >> b;
57         add_q(a,b,i);
58         add_q(b,a,i);
59     }
60     for(int i = 1;i <= n;i ++) fa[i] = i;
61     tarjan(1);
62     for(int i = 1;i <= m;i ++){ cout<<ans[i]<<endl; }
63     return 0;
64 }

4. 树剖

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3
 4 const int maxn=2e3+50;
 5 int cnt, size[maxn], f[maxn], dep[maxn], dis[maxn], w[maxn][maxn], son[maxn], top[maxn];
 6 std::vector<int> G[maxn];
 7 void dfs1(int u,int fa){
 8     size[u]=1; dep[u]=dep[fa]+1; f[u]=fa;
 9     dis[u]=dis[fa]+w[fa][u];
10     for(int i=0;i<G[u].size();i++){
11         int v=G[u][i]; if(v==fa) continue;
12         dfs1(v,u);
13         size[u]+=size[v];
14         if(size[v]>size[son[u]]) son[u]=v;
15     }
16 }
17
18 void dfs2(int u,int t){
19     top[u]=t;
20     if(son[u]) dfs2(son[u],t);
21     for(int i=0;i<G[u].size();i++){
22         int v=G[u][i];
23         if(v!=f[u]&&v!=son[u]) dfs2(v,v);
24     }
25 }
26
27 int LCA(int x,int y){
28     while(top[x]!=top[y]){
29         if(dep[top[x]]>dep[top[y]]) x=f[top[x]];
30         else y=f[top[y]];
31     }
32     return dep[x]<dep[y]? x: y;
33 }
34 int main(){
35     ios::sync_with_stdio(0);
36     cin.tie(0); cout.tie(0);
37     int n,q; cin>>n>>q;
38     for(int i=1;i<n;i++){
39         int u,v,we; cin>>u>>v>>we;
40         G[u].push_back(v);
41         G[v].push_back(u);
42         w[u][v]=w[v][u]=we;
43     }
44     dfs1(1,1); dfs2(1,1);
45     for(int i=0;i<q;i++){
46         int u,v; cin>>u>>v;
47         int lca=LCA(u,v);
48         cout<<dis[u]+dis[v]-2*dis[lca]<<endl;
49     }
50     return 0;
51 }

原文地址:https://www.cnblogs.com/noobimp/p/12001114.html

时间: 2024-08-04 11:39:31

51nod2621 树上距离一题四解ST表+倍增+Tarjan+树剖的相关文章

【BZOJ3784】树上的路径 点分治序+ST表

[BZOJ3784]树上的路径 Description 给定一个N个结点的树,结点用正整数1..N编号.每条边有一个正整数权值.用d(a,b)表示从结点a到结点b路边上经过边的权值.其中要求a<b.将这n*(n-1)/2个距离从大到小排序,输出前M个距离值. Input 第一行两个正整数N,M 下面N-1行,每行三个正整数a,b,c(a,b<=N,C<=10000).表示结点a到结点b有一条权值为c的边. Output 共M行,如题所述. Sample Input 5 10 1 2 1

算法详解——st表

st表是解决区间RMQ(区间最值问题)的一类算法,时间复杂度为O(nlogn)的预处理和O(1)的查询,其主要运用了类似倍增的思想... 总体来说,st表的用处还是挺大的,代码也比较短,容易记... st表 若现在给定一个长度为n的序列A,每次给定两个数l,r,求出A[l]~A[r]中的最大值... 那么我们考虑怎么做,首先是朴素做法,每次询问最大值时用for循环从l到r跑一遍,每次循环复杂度为O(r - l) 那有没有一种算法可以让我们以O(1)的复杂度就知道最大值呢? 这时我们引进st表算法

codeforce 1175E Minimal Segment Cover ST表 倍增思想

这题太巧妙了. 题意是,给定2*10^5个区间.然后2*10^5组询问,每次询问一个区间,问至少需要几个给定区间,才能将其完全覆盖.坐标范围5*10^5. 如果只有一个询问区间,是经典的贪心问题.我们每次选择,尽可能覆盖的靠右的区间. 但是这题显然贪心的话,时间是不够的. 考虑使用倍增进行预处理. 我们用dp[i][o]表示从i点开始,选择o个区间,能覆盖到最远哪个点.为-1,则表示不存在. 那么显然如果dp[i][o - 1] != -1 时,dp[i][o] = dp[dp[i][o - 1

HDU 2586 How far away ? &lt;&lt; LCA转RMQ+ST表 求树上任两点最短距离裸题

此题还有LCA+tarjin离线查询做法,详见这里 关于ST表 解决RMQ问题,dp[i][j]表示从第i位开始长度为(1<<j)的区间的最值 维护的时候采用倍增思想,维护dp[i][j+1]=opt(dp[i][j],dp[i+(1<<j)][j]) 查询的时候,两端点为l,r,则长度len=r-l,寻找一个k,使(1<<k)大于等于len/2,这样就使得 [l,l+(1<<k)]和[r-(1<<k),r]覆盖整个区间 然后此时,就可以直接用s

200道历年逻辑推理真题详解

200道历年逻辑推理真题详解 01.粮食可以在收割前在期货市场进行交易.如果预测谷物产量不足,谷物期货价格就会上升:如果预测谷物丰收,谷物期货价格就会下降.今天早上,气象学家们预测从明天开始谷物产区里会有非常需要的降雨.因为充分的潮湿对目前谷物的存活非常重要,所以今天的谷物期货价格会大幅下降. 下面哪个,如果正确,最严重地削弱了以上的观点? A.在关键的授粉阶段没有接受足够潮湿的谷物不会取得丰收. B.本季度谷物期货价格的波动比上季度更加剧烈. C.气象学家们预测的明天的降雨估计很可能会延伸到谷

51Nod.1766.树上最远点对(树的直径 RMQ 线段树/ST表)

题目链接 \(Description\) 给定一棵树.每次询问给定\(a\sim b,c\sim d\)两个下标区间,从这两个区间中各取一个点,使得这两个点距离最远.输出最远距离. \(n,q\leq10^5\). \(Solution\) 一个集合直径的两端点,在被划分为两个集合后一定是两个集合直径的四个端点中的两个. 即假设将\(S\)分为两个集合后,另外两个集合的直径的两端点分别为a,b和c,d,那么\(S\)集合的直径的两端点一定是a,b,c,d中的两个. 证明类似树的直径. 所以信息可

分享软件设计师教程第二三四版本+真题详解+其他考试资料下载

软件设计师教程+真题详解+其他考试资料,教程有第二版第三版第四版,带完整目录. 下载地址:网盘下载 原文地址:https://www.cnblogs.com/milugogo/p/12243121.html

LeetCode Go 并发题详解:交替打印字符串

原文地址:https://mp.weixin.qq.com/s/K032xlARjiyS8ecJrqZXaA 本题 LeetCode 链接: https://leetcode.com/problems/fizz-buzz-multithreaded/ 本题题目 给定一个数列从 1 ~ n,依序输出,但是: 如果 n 可以被 3 整除,输出 "fizz" 如果 n 可以被 5 整除,输出 "buzz" 如果 n 同时可以被 3 与 5 整除,输出 "fizz

说一说ST表 讲一讲水题

ST表 一.算法介绍 如何快速求解RMQ问题呢?暴力复杂度O(n),线段树复杂度O(n)~O(logn),要是数据规模达到10^7或者更高呢?我们需要一种可以做到O(1)查询的算法,这时就可以用到ST表. 我们用 f[i][j] 表示从 j 位置开始往右 2^i 个数内的最大值,用 g[i][j] 表示从j位置开始往左 2^i 个数内的最大值.所以 f[0][j] , g[0][j] 就为 j 位置上的数,可以在预处理中O(n)处理掉. 接下来我们要求出每个位置的每个 2^i 区间的最大值.可以