2 条题解

  • 0
    @ 2025-10-8 16:58:16

    题目分析(根据代码逻辑推测)

    该题要求对一棵树中每个节点的点权进行处理,计算每个点权值对应的“路径上出现次数”,具体为:对于每个节点ians[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;
    }
    

    代码说明

    1. 数据结构:使用邻接表G存储树结构,树状数组c用于高效维护路径上点权的计数(单点更新+前缀查询)。
    2. 核心逻辑:通过DFS遍历树,进入节点时将其点权加入树状数组,记录当前路径上该点权的出现次数;回溯时移除该点权,确保子树遍历不影响父节点路径。
    3. 点权分配:通过w[pi] = i将每个节点的点权设置为唯一值i,便于结果数组ans的索引。
    4. 时间复杂度:DFS遍历树的时间复杂度为O(n),树状数组的更新和查询复杂度为O(log n),整体复杂度为O(n log n),适用于n=1e5的规模。
    • 0
      @ 2025-10-8 16:58:05
      #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

      *【树状数组+DFS】统计点i到根路径点权比wi小的点数[USACO10FEB] Slowing down G

      信息

      ID
      1693
      时间
      1000ms
      内存
      128MiB
      难度
      6
      标签
      递交数
      88
      已通过
      28
      上传者