2 条题解
-
0
题目分析(根据代码逻辑推测)
该题要求对一棵树中每个节点的点权进行处理,计算每个点权值对应的“路径上出现次数”,具体为:对于每个节点
i,ans[i]表示以节点i为点权值时,在从根节点到i的路径上(不包含子树)该点权值出现的次数。代码实现
#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 10; vector<int> G[N]; // 邻接表存储树 int n, m, w[N], c[N], ans[N]; // w[x]为点x的点权,c为树状数组,ans存储结果 // 树状数组单点更新:c[x] += k void add(int x, int k) { for (; x <= n; x += x & -x) c[x] += k; } // 树状数组前缀查询:sum(1..x) int sum(int x) { int res = 0; for (; x >= 1; x -= x & -x) res += c[x]; return res; } // DFS遍历树,维护路径上的点权计数 void dfs(int x, int xfa) { ans[w[x]] = sum(w[x]); // 记录当前路径上w[x]的出现次数 add(w[x], 1); // 将当前点权加入树状数组 for (int y : G[x]) if (y != xfa) dfs(y, x); // 递归遍历子树 add(w[x], -1); // 回溯时移除当前点权 } int main() { scanf("%d", &n); // 读入树的边 for (int i = 1, x, y; i < n; i++) { scanf("%d%d", &x, &y); G[x].push_back(y); G[y].push_back(x); } // 读入点权分配:w[pi] = i,即点pi的点权为i for (int i = 1, pi; i <= n; i++) { scanf("%d", &pi); w[pi] = i; } dfs(1, 0); // 从根节点1开始DFS // 输出每个点权对应的结果 for (int i = 1; i <= n; i++) printf("%d\n", ans[i]); return 0; }代码说明
- 数据结构:使用邻接表
G存储树结构,树状数组c用于高效维护路径上点权的计数(单点更新+前缀查询)。 - 核心逻辑:通过DFS遍历树,进入节点时将其点权加入树状数组,记录当前路径上该点权的出现次数;回溯时移除该点权,确保子树遍历不影响父节点路径。
- 点权分配:通过
w[pi] = i将每个节点的点权设置为唯一值i,便于结果数组ans的索引。 - 时间复杂度:DFS遍历树的时间复杂度为O(n),树状数组的更新和查询复杂度为O(log n),整体复杂度为O(n log n),适用于n=1e5的规模。
- 数据结构:使用邻接表
-
0
#include<bits/stdc++.h> using namespace std; const int N=1e5+10; vector<int> G[N]; int n,m,w[N],c[N],ans[N]; void add(int x,int k){for(;x<=n;x+=x&-x)c[x]+=k;} int sum(int x){int res=0;for(;x>=1;x-=x&-x)res+=c[x];return res;} void dfs(int x,int xfa) { ans[w[x]]=sum(w[x]);//此时c数组中只保留 点x到根的路径上所有点 的影响 add(w[x],1); for(int y:G[x])if(y!=xfa)dfs(y,x); add(w[x],-1); } int main() { scanf("%d",&n); for(int i=1,x,y;i<n;i++) { scanf("%d%d",&x,&y); G[x].push_back(y); G[y].push_back(x); } for(int i=1,pi;i<=n;i++) { scanf("%d",&pi); w[pi]=i;//相当于点pi的点权为i } dfs(1,0); for(int i=1;i<=n;i++)printf("%d\n",ans[i]); return 0; }
- 1
信息
- ID
- 1693
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 6
- 标签
- 递交数
- 88
- 已通过
- 28
- 上传者