首页 > 其他分享 >9. 景区导游-树上前缀和&&最近公共祖先

9. 景区导游-树上前缀和&&最近公共祖先

时间:2024-04-06 12:30:41浏览次数:23  
标签:dep 前缀 int tu 导游 fa && 节点

9.景区导游 - 蓝桥云课 (lanqiao.cn)

6 4
1 2 1
1 3 1
3 4 2
3 5 2
4 6 3
2 6 5 1

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
//tu动态数组用来存图,相当于一条绳子上面有好几个结,每个结都各自连了一条链子
//vector <pair<to,value>>tu[maxn] maxn->节点最大数量,to->联通的节点,value->权值
vector <pair<int,int>>tu[100002];
//dep存节点的深度,把图看成树
//fa[u][i]存u结点往上跳2^i次幂后是哪个节点
//s存边前缀和,以游览路线的第一个景点为根节点,把其他每一个节点到根节点的权值和存到s数组里
int dep[100002],fa[100002][19],s[100002];
//树上前缀和(在最近公共祖先的板子上加以改动就行)+最近公共祖先
//dfs直接套模板
void dfs(int u,int father){//也可以说是预处理节点信息
	dep[u]=dep[father]+1;
	fa[u][0]=father;
	for(int i=1;i<=18;i++){
		fa[u][i]=fa[fa[u][i-1]][i-1];
		if(!fa[u][i]) break;
	}
	for(int i=0;i<tu[u].size();i++){
//		这里是和父节点判断
		if(tu[u][i].first==father) continue;
//		下面这一行不是模板里的,不是求最近公共祖先的模板
//		而是求树上前缀和的(递推就求出来了)
//		该点到根节点的前缀和=其父节点的前缀和+父节点到该点的权值
		s[tu[u][i].first]=s[u]+tu[u][i].second;
		dfs(tu[u][i].first,u);
	}
}
//lca函数能返回其两点的最近公共祖先
//lca一点变化都没有直接套模板
int lca(int u,int v){
	if(dep[u]<dep[v]) swap(u,v);
	for(int i=18;i>=0;i--){
//		别忘了这里是判断深度dep
		if(dep[fa[u][i]]>=dep[v])	u=fa[u][i];
	}
	if(u==v) return u;
	for(int i=18;i>=0;i--){
		if(fa[u][i]!=fa[v][i]){
			u=fa[u][i];
			v=fa[v][i];
		}
	}
	return fa[v][0];
}
//计算u节点到v节点的权值
//因为是边前缀和,所以两个节点之间的前缀和=两点的前缀和相加-两倍的其最近公共祖先的前缀和
int cal(int u,int v){
	return s[u]+s[v]-2*s[lca(u,v)];
}
void solve(){
	int n,k,shunxu[100002],sum=0;
	cin>>n>>k;
//	存图
	for(int i=0;i<n-1;i++){
		int u,v,t;
		cin>>u>>v>>t;
		tu[u].push_back({v,t});
		tu[v].push_back({u,t});
	}
//	存游览线路的顺序
	for(int i=0;i<k;i++){
		cin>>shunxu[i];
	}
//	遍历一遍,好把前缀和啥的都存起来了
//	记住,这里就调用了一次,然后他在递归
	dfs(shunxu[0],0);
//	把总线路的权值都加一块存起来
	for(int i=0;i<k-1;i++){
		sum+=cal(shunxu[i],shunxu[i+1]);
	}
//	依次计算跳第i个景点后的权值和
	for(int i=0;i<k;i++){
//		如果是跳过第一个景点,那只用把第一条线减掉
		if(i==0){
			cout<<sum-cal(shunxu[0],shunxu[1])<<" ";
		}
//		如果是跳过最后一个景点,那只用把最后一条线减掉
		else if(i==k-1){
			cout<<sum-cal(shunxu[k-2],shunxu[k-1])<<" ";
		}
//		如果是跳过中间景点,那需要把该节点左右两边的线减掉,再加上该点左右两个景点之间的路径
		else{
			cout<<sum-cal(shunxu[i-1],shunxu[i])-cal(shunxu[i],shunxu[i+1])+cal(shunxu[i-1],shunxu[i+1])<<" ";
		}
	}
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	solve();
	return 0;
}

标签:dep,前缀,int,tu,导游,fa,&&,节点
From: https://blog.csdn.net/weixin_73214301/article/details/137407257

相关文章

  • 前缀和
    题目LeetCode力扣难度303.RangeSumQuery-Immutable303.区域和检索-数组不可变......
  • 208. 实现 Trie (前缀树)
    classTrie{Trie[]chs=newTrie[26];intcnt=0;publicTrie(){}publicvoidinsert(Stringword){Trieroot=this;for(charch:word.toCharArray()){if(root.chs[ch-'a']==null){......
  • 前缀异或和
    异或是可以用前缀和来维护的,因为异或有一个重要的性质x^x=0设preXor[i]=a[0]^a[1]^a[2]^a[3]^a[4]^.....^a[i]那么给定一个[l,r]范围的区间求a[l,r]的异或和,我们就可以利用前缀异或和来求解preXor(l,r)=preXor(0,r)^preXor(0,l-1)=preXor[r]^p......
  • Leetcode 【930. 和相同的二元子数组】【统计「优美子数组」】【974. 和可被 K 整除的
    这道题目是经典的求子数组之和=goal的个数,用map维护。但是笔者在实现的过程中发现0的情况不是很好出来,问题在于mp[sum]和sum+=num的代码语句存在位置问题。后来看了下代码还是自己没有考虑清楚。这种类型的题目就是要想清楚你的做法,以及边界条件。classSolution{public:......
  • Nginx配置静态代理/静态资源映射时root与alias的区别,带前缀映射用alias
    场景Nginx搭建静态资源映射实现远程访问服务器上的图片资源:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/117283572以上在配置静态资源映射时使用的如下配置     location/{           root  D:/pic_old/;           try_......
  • 前缀和与差分数组
    目录一维前缀和二维前缀和差分数组差分数组反推出原始数组差分数组模板前缀和应用场景:原始数组不会被修改的情况下,频繁查询某个区间的累加和。eg:计算数组下标2到5的数组和,原本用for循环,有了前缀和直接用5的前缀和减去2的前缀和得到答案,可以将O(n)的复杂度降为O(1)一维前缀和......
  • 前缀和算法讲解(二)
    首先,大家看一下一维的前缀和:https://blog.csdn.net/hjyowl/article/details/136580832?spm=1001.2014.3001.5502今天,我们讲解一下二维的前缀和.先看题:输入一个 n 行 m 列的整数矩阵,再输入 q 个询问,每个询问包含四个整数 x1,y1,x2,y2,表示一个子矩阵的左上角坐标和右下......
  • 蓝桥杯算法基础(29)字符串匹配(RabinKarp)(KMP)(前缀树,字典树,trie,后缀数组,高度数组)
     RabinKarpRabinKarpS:ABABABm个P:ABBn个1.朴素算法,挨个匹配2.哈希法hash->滚动哈希c0*31^2+c1*31^1+c2类似于进制的求法求hash值(c0*31+c1)*31+c2hash(p)=o(n)hash(s)=o(m*n)privatestaticvoidmatch(Stringp,Strings){longhash_p=hash(p);......
  • 高维前缀和/SOS DP 学习笔记
    JOISC2023D2T2Council注意到,钦定一个人为主席后,对于此时得票数大于\(\lfloor\frac{n}{2}\rfloor\)的议案,不管怎么选副主席,均能通过;对于此时得票数小于\(\lfloor\frac{n}{2}\rfloor\)的议案,不管怎么选副主席,均不能通过。所以需要考虑的只有此时得票数恰好等于\(\lfloo......
  • 二 562. 壁画 (前缀和)
    562.壁画(前缀和)思路:壁画最终应是长度为mid=(N+1)/2的连续一段,而被摧毁的墙则在两边,故以终点为标志从mid遍历到N,确定最大的一段美观总分,同时因为多次计算一段美观评分耗时多,可提前计算出美观评分的前缀和,然后对应的美观总分=sum[i]-sum[i-mid]。importjava.util.*;p......