1 条题解

  • 0
    @ 2026-1-29 9:49:03

    D53 树的直径 建图技巧+两次DFS P2610 [ZJOI2012] 旅游

    // 树的直径 建图技巧+两次DFS O(n)
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=200005;
    int h[N],to[N<<1],ne[N<<1],idx;
    void add(int a,int b){
      to[++idx]=b; ne[idx]=h[a]; h[a]=idx;
      to[++idx]=a; ne[idx]=h[b]; h[b]=idx;
    }
    int n,d[N],p,ans;
    map<pair<int,int>,int> mp;
    
    void dfs(int x,int f){
      if(d[x]>d[p]) p=x; //记录直径的端点
      for(int i=h[x];i;i=ne[i]){
        int y=to[i];
        if(y!=f){
          d[y]=d[x]+1;   //记录从根到y的距离
          dfs(y,x);
        }
      }
    }
    int main(){
      ios::sync_with_stdio(0);cin.tie(0);
      cin>>n;
      for(int i=1,p,q,r;i<=n-2;++i){ //枚举三角形的编号,编号做树的节点
        cin>>p>>q>>r;
        if(p>q) swap(p,q);
        if(p>r) swap(p,r);
        if(q>r) swap(q,r);          //三角形顶点{p,q,r}升序排列,免去判重
        if(!mp[{p,q}]) mp[{p,q}]=i; //若当前边未遍历,则用当前三角形的编号标记
        else add(i,mp[{p,q}]);      //若当前边已遍历,说明当前三角形与已遍历过的三角形相邻,则把两三角形的编号用树边相连
        if(!mp[{p,r}]) mp[{p,r}]=i;
        else add(i,mp[{p,r}]);
        if(!mp[{q,r}]) mp[{q,r}]=i;
        else add(i,mp[{q,r}]);
      }
      dfs(1,0); d[p]=0;
      dfs(p,0); ans=d[p]+1; //答案是直径上的点数=边数+1
      cout<<ans;
    }
    
    • 1

    信息

    ID
    4322
    时间
    1000ms
    内存
    512MiB
    难度
    10
    标签
    递交数
    2
    已通过
    2
    上传者