2 条题解

  • 0
    @ 2026-6-14 0:29:48

    // LCA+树上差分 O(mlogn)
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=100010,M=200010;
    int h[N],to[M],ne[M],idx;
    void add(int u,int v){
      to[++idx]=v,ne[idx]=h[u],h[u]=idx;
    }
    int n,m,ans;
    int dep[N],fa[N][17],d[N];
    
    void dfs(int u,int f){ //预处理dep,fa数组
      dep[u]=dep[f]+1; fa[u][0]=f;
      for(int i=1; i<=16; i++) fa[u][i]=fa[fa[u][i-1]][i-1];
      for(int i=h[u]; i; i=ne[i]){
        int v=to[i];
        if(v!=f) dfs(v,u);
      }
    }
    int lca(int u,int v){ //求lca
      if(dep[u]<dep[v]) swap(u,v);
      for(int k=16; k>=0; k--)if(dep[fa[u][k]]>=dep[v]) u=fa[u][k];
      if(u==v) return u;
      for(int k=16; k>=0; k--)if(fa[u][k]!=fa[v][k]) u=fa[u][k],v=fa[v][k];
      return fa[u][0];
    }
    int dfs2(int u,int f){ //对子树的差分求和
      int sum=d[u];
      for(int i=h[u]; i; i=ne[i]){
        int v=to[i];
        if(v==f) continue;
        int s=dfs2(v,u);
        if(s==0) ans+=m;
        else if(s==1) ans++; //树边(u,v)的贡献
        sum+=s;
      }
      return sum; //u子树的结点权值和,即边(u,fa)被覆盖次数
    }
    int main(){
      scanf("%d%d",&n,&m);
      for(int i=0,u,v; i<n-1; i++){
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
      }
      dfs(1,0);
      for(int i=0,u,v; i<m; i++){
        scanf("%d%d",&u,&v);
        d[u]++,d[v]++,d[lca(u,v)]-=2; //树上差分
      }
      dfs2(1,0); //差分求和
      printf("%d\n",ans);
    }
    
    • 0
      @ 2025-10-8 16:50:47
      #include <bits/stdc++.h>
      #define eb emplace_back
      using namespace std;
      const int N=1e5+10;
      vector<int>G[N];
      int f[N][20],dep[N],D;
      void dfs(int x,int fa)
      {
          dep[x]=dep[fa]+1;
          f[x][0]=fa;for(int i=1;i<=D;i++)f[x][i]=f[f[x][i-1]][i-1];
          for(auto y:G[x])if(y!=fa)dfs(y,x);
      }
      int lca(int x,int y)
      {
          if(dep[x]<dep[y])swap(x,y);
          for(int i=D;i>=0;i--)if(dep[f[x][i]]>=dep[y])x=f[x][i];
          if(x==y)return y;
          for(int i=D;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
          return f[x][0];
      }
      int d[N];
      void dfs2(int x,int fa)
      {
          for(auto y:G[x])if(y!=fa)
          {
              dfs2(y,x);
              d[x]+=d[y];
          }
      }
      int main()
      {
          int n,m;scanf("%d%d",&n,&m);
          for(int i=1,x,y;i<n;++i)
          {
              scanf("%d%d",&x,&y);
              G[x].eb(y);G[y].eb(x);
          }
          dep[0]=0;D=log2(n);dfs(1,0);
          memset(d,0,sizeof(d));
          for(int i=1,x,y;i<=m;i++)
          {
              scanf("%d%d",&x,&y);
              d[x]++,d[y]++;
              d[lca(x,y)]-=2;
          }
          dfs2(1,0);
          
          int ans=0;
          for(int i=2;i<=n;i++)
          {
              if(d[i]==0)ans+=m;
              if(d[i]==1)ans++;
          }
          printf("%d\n",ans);
          return 0;
      }
      
      • 1

      D156 *【树上边差分】删2边使树不连通[闇の連鎖]

      信息

      ID
      486
      时间
      1000ms
      内存
      128MiB
      难度
      5
      标签
      递交数
      74
      已通过
      27
      上传者