Sergey and Subway
Sergey Semyonovich is a mayor of a county city N and he used to spend his days and nights in thoughts of further improvements of Nkers' lives. Unfortunately for him, anything and everything has been done already, and there are no more possible improvements he can think of during the day (he now prefers to sleep at night). However, his assistants have found a solution and they now draw an imaginary city on a paper sheet and suggest the mayor can propose its improvements.
Right now he has a map of some imaginary city with n subway stations. Some stations are directly connected with tunnels in such a way that the whole map is a tree (assistants were short on time and enthusiasm). It means that there exists exactly one simple path between each pair of station. We call a path simple if it uses each tunnel no more than once.
One of Sergey Semyonovich's favorite quality objectives is the sum of all pairwise distances between every pair of stations. The distance between two stations is the minimum possible number of tunnels on a path between them.
Sergey Semyonovich decided to add new tunnels to the subway map. In particular, he connected any two stations u and v that were not connected with a direct tunnel but share a common neighbor, i.e. there exists such a station w that the original map has a tunnel between u and w and a tunnel between w and v. You are given a task to compute the sum of pairwise distances between all pairs of stations in the new map.
Input
The first line of the input contains a single integer
n
(2≤n≤200000) — the number of subway stations in the imaginary city drawn by mayor’s assistants. Each of the following
n−1 lines contains two integers ui and vi (1≤ui,vi≤n, ui≠vi), meaning the station with these indices are connected with a direct tunnel.
It is guaranteed that these n stations and n−1 tunnels form a tree.
Output
Print one integer that is equal to the sum of distances between all pairs of stations after Sergey Semyonovich draws new tunnels between all pairs of stations that share a common neighbor in the original map.
Examples
input
4
1 2
1 3
1 4
output
6
input
4
1 2
2 3
3 4
output
7
题意:给出一个树,把树上任意两个相隔一个点的点加一条边,问加完边之后任意两点的距离和是多少.
思路:51nod上有这样一个题目,让求树上每个点到其他所有节点的距离和,打印出n个数,代表答案.
我们可以先一遍dfs求出每个节点到他的所有子节点的距离和,那么根节点存的就是他到树上每个节点的
距离和,这样根节点的儿子就可以由他转移过来,就可以求出题目要求的答案来.
这题也可以这样做,稍微不同的是往下dfs也好,往下转移也好,都是向孙子转移,父亲会由他的爷爷
dfs过来,往下转移的时候也得向孙子.这里的根必须是叶子节点,这样可以避免很多问题,而根节点的儿子
需要在单独向下转移,因为他跟根节点都是独立的,也可以看成根.
后面讲一个简单思路.
代码:
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 2e5+5;
struct node
{
int u,v,ne;
} e[maxn<<1];
int n;
int head[maxn],len;
int ve[maxn],num[maxn];
ll d[maxn];
ll ans;
void add(int u,int v)
{
e[len].u = u;
e[len].v = v;
e[len].ne = head[u];
head[u] = len++;
}
void dfs(int x,int p)
{
ve[x] = 1;
for(int i = head[x];~i;i = e[i].ne)
{
int v = e[i].v;
if(v == p) continue;
dfs(v,x);
for(int j = head[v];j!= -1;j = e[j].ne)
{
int sv = e[j].v;
if(sv == x) continue;
d[x]+= d[sv]+ve[sv];//distance to grandson
}
d[x]++;//distance to son
ve[x]+= ve[v];
}
return ;
}
void dfs2(int x,int p)
{
ans+= d[x];
for(int i = head[x];~i;i = e[i].ne)
{
int v = e[i].v;
if(v == p) continue;
for(int j = head[v];j!= -1;j = e[j].ne)
{
int sv = e[j].v;
if(sv == x) continue;
d[sv]+= d[x]-d[sv]-ve[sv]+n-ve[sv]-(ve[v]-ve[sv]);
dfs2(sv,v);
}
if(p == 0)// if x is root,the son is independent
{
d[v]++;
dfs2(v,x);
}
}
return ;
}
int main()
{
mem(head,-1);
cin>>n;
for(int i = 1,x,y;i< n;i++)
{
scanf("%d %d",&x,&y);
add(x,y);
add(y,x);
num[x]++;
num[y]++;
}
int st;
for(int i = 1;i<= n;i++)
{
if(num[i] == 1)
{
st = i;
break;
}
}
dfs(st,0);
dfs2(st,0);
cout<<ans/2<<endl;
return 0;
}
如果是求树上任意两点之间的距离和,我们有一个比较简单的做法,就是不考虑点,考虑边.
很显然,每条边被使用的次数是固定的,即边的一端的节点数目乘以另一端的节点数目.这样我们就能求
树上任意两点之间的距离和了,这道题就是一个变形.我们想,假如一个节点在树上距离另一个节点偶数条边,
那么他是不是可以两个两个地跳过去,只需要走一半的路程就到了.假如有奇数条边,两个两个条,最后难免
剩一条边,其实就是(边数+1)/2.所以,假如我们给树规定一个层次的话,只有奇数层的节点和偶数层的节点
的路径会出现这种状况,其余的都能两步两步跳到.所以,我们只需要把这样的情况多+1,最后结果/2即可.
代码:
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 2e5+5;
struct node
{
int u,v,ne;
} e[maxn<<1];
int n;
int head[maxn],len;
int ve[maxn],b[maxn];
void add(int u,int v)
{
e[len].u = u;
e[len].v = v;
e[len].ne = head[u];
head[u] = len++;
}
void dfs(int x,int p,int k)
{
ve[x] = 1;
b[x] = k;
for(int i = head[x];~i;i = e[i].ne)
{
int v = e[i].v;
if(v == p) continue;
dfs(v,x,k^1);
ve[x]+= ve[v];
}
return ;
}
int main()
{
mem(head,-1);
cin>>n;
for(int i = 1,x,y;i< n;i++)
{
scanf("%d %d",&x,&y);
add(x,y);
add(y,x);
}
dfs(1,0,0);
ll ans = 0,sum = 0;
for(int i = 1;i<= n;i++)
{
ans+= 1ll*ve[i]*(n-ve[i]);
sum+= b[i];
}
ans+= sum*(n-sum);
cout<<ans/2<<endl;
return 0;
}