异或路径(dfs,点贡献)

本文介绍了一种使用树形DP算法解决路径贡献问题的方法,通过对树中每个点进行深度优先搜索,计算出该点及其子树的大小,进而得出经过该点的所有可能路径的次数,最终判断出哪些点对答案有贡献。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
传送门

思路:从题目中我们可以很明显知道要想知道某点是否对答案有贡献,那么只要判断在最短路中经过该点的次数。
这里借鉴了一个大佬的思路:
在这里插入图片描述
首先通过dfs可以求出树中每个点子树的个数,那么经过某个点的三种情况如下
(1)该点的父亲节点到该点及其子节点
(2)该店的子节点到该点及父节点
(3)该点到剩下n-1个节点

(1)情况可以计算该点及全部子树大小z,经过该点(n-z)*z
(2)情况可以分别计算该点子数大小k,经过该点(n-k)*k
(3)情况 n-1
最后由于i->j及j->i重复了,所以总次数除以2便可以计算出经过该点次数,从而判断是否有影响。

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;
int n;
int size[maxn];
int head[maxn];
int cnt;
struct Node{
	int to;
	int val;
	int next;
}a[maxn];
int w[maxn];
int solve;

int dfs(int root,int fa){
	size[root]=1;
	int ans=0;
	for(int i=head[root];~i;i=a[i].next){
		if(a[i].to==fa) continue;
		int k=dfs(a[i].to,root);
		size[root]+=k;
		ans+=(k)*(n-k);
	}
	ans+=n-1; 
	ans+=(n-size[root])*size[root];
	ans>>=1;
	if(ans&1) solve^=w[root];
	return size[root]; 
}

void Add(int u,int v,int val){
	a[cnt].next=head[u];
	a[cnt].val=val;
	a[cnt].to=v;
	head[u]=cnt++;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	memset(head,-1,sizeof(head));
	cin>>n;
	int u,v,val;
	cnt=0;
	for(int i=1;i<n;i++){
		cin>>u>>v;
		Add(u,v,0);
		Add(v,u,0);
	}
	for(int i=1;i<=n;i++){
		cin>>w[i];
	}
	solve=0;
	int sum=dfs(1,0);
	cout<<solve<<endl;
	return 0;
} 
### C++ 异或最短路径算法实现 异或最短路径问题通常涉及在图中寻找一条从起到终路径,使得路径上所有边权值的异或和最小。这类问题可以通过结合图论中的最短路径算法(如Dijkstra算法)与前缀异或的概念来解决。 以下是一个基于Dijkstra算法的C++实现,用于计算异或最短路径: ```cpp #include <bits/stdc++.h> using namespace std; struct Edge { int to; int weight; }; const int MAXN = 1e4 + 5; vector<Edge> graph[MAXN]; int n, m, s, t; long long dist[MAXN][2]; // dist[u][0]表示不取反的最短距离,dist[u][1]表示取反的最短距离 bool visited[MAXN][2]; void addEdge(int u, int v, int w) { graph[u].push_back({v, w}); } void dijkstraXOR() { priority_queue<pair<long long, pair<int, int>>, vector<pair<long long, pair<int, int>>>, greater<>> pq; for (int i = 0; i <= n; ++i) { dist[i][0] = dist[i][1] = LLONG_MAX; } dist[s][0] = 0; pq.push({0, {s, 0}}); while (!pq.empty()) { auto current = pq.top(); pq.pop(); long long d = current.first; int node = current.second.first; int xorFlag = current.second.second; if (visited[node][xorFlag]) continue; visited[node][xorFlag] = true; for (auto &edge : graph[node]) { int neighbor = edge.to; int weight = edge.weight; int newXor = d ^ weight; if (newXor < dist[neighbor][0]) { dist[neighbor][0] = newXor; pq.push({newXor, {neighbor, 0}}); } // 如果需要考虑异或路径的特殊情况,可以在此处扩展逻辑 } } } int main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n >> m >> s >> t; for (int i = 0; i < m; ++i) { int u, v, w; cin >> u >> v >> w; addEdge(u, v, w); addEdge(v, u, w); // 如果是无向图 } dijkstraXOR(); if (dist[t][0] == LLONG_MAX) { cout << "-1\n"; // 无法到达目标节 } else { cout << dist[t][0] << "\n"; } return 0; } ``` ### 算法说明 上述代码实现了基于Dijkstra算法的异或最短路径计算方法。关键如下: 1. 使用优先队列(`priority_queue`)来保证每次扩展的节都是当前具有最小异或距离的节[^1]。 2. `dist[u][0]` 表示从起到节 `u` 的异或最短路径距离,`dist[u][1]` 可以扩展为其他状态(如果需要更复杂的异或路径计算)[^2]。 3. 对于每条边 `(u, v, w)`,更新目标节 `v` 的异或距离为 `d ^ w`,其中 `d` 是当前节 `u` 的异或距离[^3]。 ### 注意事项 - 如果数据范围较大(例如 `n` 和 `m` 接近上限),需要优化存储结构和访问方式,例如使用邻接表代替邻接矩阵[^3]。 - 在实际应用中,可能需要根据具体问题调整算法逻辑,例如处理负权边或有向图的情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值