题目:题目链接
题意:求三颗不同子树上点的组合的个数
分析:先求出在一条线上的三个点的数目,然后拿n*(n - 1)*(n - 2)/6减掉;对于树上的三个点,假设A-B-C,那么
对于AC,我们就可以枚举B:
#pragma comment(linker, "/STACK:16777216")
#include <iostream>
#include <cstdio>
#include <string>
#include <string.h>
#include <map>
#include <vector>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
#include <functional>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <numeric>
#include <cassert>
#include <bitset>
#include <stack>
#include <ctime>
#include <list>
#define INF 0x7fffffff
#define max3(a,b,c) (max(a,b)>c?max(a,b):c)
#define min3(a,b,c) (min(a,b)<c?min(a,b):c)
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N = 100000;
int n;
int cnt;
int fronte[N];
int into[N << 1];
int behinde[N << 1];
int father[N];
int find(int u)//使用并查集
{
if (father[u] != u)
father[u] = find(father[u]);
return father[u];
}
bool merge(int a, int b)
{
if (find(a) == find(b))
return false;
father[find(a)] = find(b);
return true;
}
__int64 ans;
int size[N];
void work(int p, int u)
{
size[u] = 1;
int sum = 0;
for (int i = fronte[u]; i != -1; i = behinde[i])
{
int v = into[i];
if (v != p)
{
work(u, v);
size[u] += size[v];
ans -= (__int64)sum * size[v];
sum += size[v];
}
}
ans -= (__int64)sum * (n - size[u]);
}
void ADD(int u, int v)//加入存在的边
{
into[cnt] = v;
behinde[cnt] = fronte[u];
fronte[u] = cnt ++;
}
int main()
{
while (scanf("%d", &n) == 1)
{
cnt = 0;
memset(fronte, -1, sizeof(fronte));
for (int i = 0; i < n; ++ i)
father[i] = i;
for (int i = 0; i < n - 1; ++ i)
{
int a, b;
scanf("%d%d", &a, &b);
a--, b--;
ADD(a, b);
ADD(b, a);
merge(a, b);
}
ans = (__int64)n*(n - 1)*(n - 2)/6;
work(-1, 0);
printf("%I64d\n", ans);
}
return 0;
}
树,好晕.....