Dis2(dfs树)

该博客介绍了一个关于树形结构的问题,其中需要找出每个节点与其距离为2的其他节点的数量。通过深度优先搜索(DFS)遍历树,并在过程中更新每个节点的计数,可以计算出每个节点的邻接节点和子树中距离为2的节点数量。程序实现了这一算法,并在样例输入中得到了正确输出。

Dis2

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述 

给出一颗nn个点n−1n−1条边的树,点的编号为1,2,...,n−1,n1,2,...,n−1,n,对于每个点i(1≤i≤n)i(1≤i≤n),输出与点ii距离为22的点的个数。 

两个点的距离定义为两个点最短路径上的边的条数。 

输入描述:

 

第一行一个正整数nn。

接下来n−1n−1行每行两个正整数ui,viui​,vi​表示点ui,viui​,vi​之间有一条边。

输出描述:

输入共nn行,第ii行输出一个整数表示与点ii距离为22的点的个数。

示例1

输入

复制

4
1 2
2 3
3 4

输出

复制

1
1
1
1

说明

点1,31,3的距离为22,点2,42,4的距离为22。

备注:

1≤ui,vi≤n≤2000001≤ui​,vi​≤n≤200000

思路:

距离为2的点的个数=父亲节点的边树-1+子树边树-1

dfs遍历树就行

int n;
const int MAX=2e5+10;
vector<int>g[MAX];
int cnt[MAX];
void dfs(int u,int f){
    if(f>0) cnt[u]+=g[f].size()-1;
    for(int i=0;i<g[u].size();i++){
        int v=g[u][i];
        if(v==f) continue;
        cnt[u]+=g[v].size()-1;
        dfs(v,u);
    }
}
int  main(){
    cin>>n;
    for(int i=1;i<n;i++){
        int u,v;
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1,0);
    
    for(int i=1;i<=n;i++){
        cout<<cnt[i]<<endl;
    }
}

帮我再次调试一下#include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; int N1, N2; long long sum[MAXN];//2直径最大距离的后缀和 //================ int cnt1 = 0, head1[MAXN], cnt2 = 0, head2[MAXN]; struct star{ int nxt, to, w; }e1[MAXN * 2], e2[MAXN * 2]; void add1( int u, int v, int w ){ e1[++ cnt1].nxt = head1[u]; e1[cnt1].to = v; e1[cnt1].w = w; head1[u] = cnt1; } void add2( int u, int v, int w ){ e2[++ cnt2].nxt = head2[u]; e2[cnt2].to = v; e2[cnt2].w = w; head2[u] = cnt2; } //================star_edge int d, dis1[MAXN], dis2[MAXN];//d为最大直径 求1、2的直径 int dfs1( int u, int fa, int w ){ dis1[u] = dis1[fa] + w; int ans = u; for( int i = head1[u]; i; i = e1[i].nxt ){ int to = e1[i].to; if( to == fa ) continue; int a = dfs1( to, u, e1[i].w ); if( dis1[a] > dis1[ans] ) ans = a; } return ans; } int dfs2( int u, int fa, int w ){ dis2[u] = dis2[fa] + w; int ans = u; for( int i = head2[u]; i; i = e2[i].nxt ){ int to = e2[i].to; if( to == fa ) continue; int a = dfs2( to, u, e2[i].w ); if( dis2[a] > dis2[ans] ) ans = a; } return ans; } //================原始的直径 int dis3[MAXN], dis4[MAXN], dis5[MAXN], dis6[MAXN];//1、2直径两端点到点u的最大距离 int _1dis[MAXN], _2dis[MAXN];//最终最大的直径某一端点的距离 void dfs3( int u, int fa ){//1端点1 for( int i = head1[u]; i; i = e1[i].nxt ){ int to = e1[i].to; if( to == fa ) continue ; dis3[to] = dis3[u] + e1[i].w; dfs3( to, u ); } } void dfs4( int u, int fa ){//2端点1 for( int i = head2[u]; i; i = e2[i].nxt ){ int to = e2[i].to; if( to == fa ) continue ; dis4[to] = dis4[u] + e2[i].w; dfs4( to, u ); } } void dfs5( int u, int fa ){//1端点2 _1dis[u] = max( dis3[u], dis5[u] ); for( int i = head1[u]; i; i = e1[i].nxt ){ int to = e1[i].to; if( to == fa ) continue ; dis5[to] = dis5[u] + e1[i].w; dfs5( to, u ); } } void dfs6( int u, int fa ){//2端点2 _2dis[u] = max( dis4[u], dis6[u] ); for( int i = head2[u]; i; i = e2[i].nxt ){ int to = e2[i].to; if( to == fa ) continue ; dis6[to] = dis6[u] + e2[i].w; dfs6( to, u ); } } //================最终处理出d数组 bool chk( int i, int j ){//x为二分的b能取到的下标 return ( _1dis[i] + _2dis[j] + 1 ) < d; } int main(){ cin >> N1; for( int i = 1; i < N1; i ++ ){ int u, v; cin >> u >> v; add1( u, v, 1 ); add1( v, u, 1 ); } cin >> N2; for( int i = 1; i < N2; i ++ ){ int u, v; cin >> u >> v; add2( u, v, 1 ); add2( v, u, 1 ); } int d1_1 = dfs1( 1, 0, 0 ); int d1_2 = dfs1( d1_1, 0, 0 ); int d2_1 = dfs2( 1, 0, 0 ); int d2_2 = dfs2( d2_1, 0, 0 ); // cout << d1_1 << " " << d1_2 << " " << d2_1 << " " << d2_2 << endl; //求出直径 dfs3( d1_1, 0 ); dfs4( d2_1, 0 ); dfs5( d1_2, 0 ); dfs6( d2_2, 0 ); //求出直径到剩下点的距离 int d_1 = dis1[d1_2], d_2 = dis2[d2_2];//两棵直径的值 d = max( d_1, d_2 ); // cout << d_1 << " " << d_2 << " " << d << endl; // for( int i = 1; i <= N1; i ++ ) cout << _1dis[i] << " "; // cout << endl; // for( int i = 1; i <= N2; i ++ ) cout << _2dis[i] << " "; // cout << endl; sort( _1dis + 1, _1dis + N1 + 1 ); sort( _2dis + 1, _2dis + N2 + 1 ); for( int i = N2; i >= 1; i -- ){ sum[i] = sum[i + 1] + _2dis[i]; } int ans = 0; for( int i = 1; i <= N1; i ++ ){ int l = 0, r = min( N2, (int)1e9 ), j; while( l <= r ){ int mid = ( l + r ) / 2; if( chk( i, mid ) ) l = mid + 1, j = mid; else r = mid - 1; } j += 1; // ( N2 - j + 1 ) ans += ( j - 1 ) * d + sum[j] + ( N2 - j + 1 ) * ( _1dis[i] + 1 ); } // cout << endl; cout << ans; return 0; } 不要改变我的变量和变量名啊
07-19
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郭晋龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值