描述
题解
根据题意,这是一颗树,所以每两点之间的路径一定是唯一的。这里让求所有点到第i个结点的距离和,其实也就是其他所有结点到第i个结点的距离和。
通过观察发现,只要我们找到了一个点对应的结果,那么其他所有的点都可以通过这个结果扩展出来,利用边的关系。比如说,我们知道了第一个结点对应的结果,并且知道第一个和第二个存在连边,那么一定可以通过第一个的结果求得第二个结果……以此类推。
所以,我们先dfs,求第一个结点的对应结果(当做根,也可以是别的结点当做根),并且存储该树每个枝杈上的后代数目(包括其本身),这个数据对求其他结果至关重要,接着我们再通过第二个dfs扩展出其他结果即可。
另外附一份树归的解法(Two)……
代码
One:
#include <iostream>
#include <vector>
#include <cstdio>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 5;
int n;
ll res[MAXN];
int des[MAXN];
vector<int> node[MAXN];
void dfs(int lastPos, int pos, int power)
{
for (int i = 0; i < node[pos].size(); i++)
{
if (node[pos][i] != lastPos)
{
res[1] += (node[node[pos][i]].size() - 1) * power;
dfs(pos, node[pos][i], power + 1);
des[pos] += des[node[pos][i]];
}
}
return ;
}
void dfs_(int lastPos, int pos)
{
for (int i = 0; i < node[pos].size(); i++)
{
if (node[pos][i] != lastPos)
{
res[node[pos][i]] = res[pos] - des[node[pos][i]] + n - des[node[pos][i]];
dfs_(pos, node[pos][i]);
}
}
return ;
}
int main(int argc, const char * argv[])
{
// freopen("/Users/zyj/Desktop/input.txt", "r", stdin);
cin >> n;
int x, y;
for (int i = 1; i < n; i++)
{
scanf("%d %d", &x, &y);
node[x].push_back(y);
node[y].push_back(x);
}
res[1] = node[1].size();
for (int i = 1; i <= n; i++)
{
des[i] = 1;
}
dfs(0, 1, 2);
dfs_(0, 1);
for (int i = 1; i <= n; i++)
{
printf("%lld\n", res[i]);
}
return 0;
}
Two:
#include <iostream>
#include <cstdio>
#include <cstring>
#define MAXN 100009
using namespace std;
typedef struct
{
int a;
int next;
} point;
point p[2 * MAXN];
typedef struct
{
long long n;
long long w;
} r;
r R;
int dis[MAXN];
long long dp[2 * MAXN][2];
void DFS(int a, int last)
{
int i;
long long ans = 0, count = 0;
for (i = dis[a]; i != 0; i = p[i].next)
{
if (p[i].a != last)
{
if (dp[i][0] != -1)
{
ans += dp[i][0] + dp[i][1];
count += dp[i][1];
}
else
{
DFS(p[i].a, a);
dp[i][0] = R.w;
dp[i][1] = R.n;
ans += R.w + R.n;
count += R.n;
}
}
}
R.n = count + 1;
R.w = ans;
return ;
}
int main ()
{
int N, k = 1, a, b;
memset(dp, -1, sizeof(dp));
scanf("%d", &N);
for (int i = 1; i < N; i++)
{
scanf("%d%d", &a, &b);
p[k].a = a;
p[k].next = dis[b];
dis[b] = k++;
p[k].a = b;
p[k].next = dis[a];
dis[a] = k++;
}
for (int i = 1, sz = N + 1; i < sz; i++)
{
DFS(i, 0);
printf("%lld\n", R.w);
}
return 0;
}