题意:求一棵树中不在一条链中的三个点的对数。
转化一下,用总对数减去在一条链上的三点对数即可。
考虑经过根节点,然后可能是不同的子树中各选一个;或者是子树中选一个,然后当前节点为根的子树以外的节点选一个。
这样不重不漏
代码简单。
#define maxn 100005 struct node { int v,next; }; node e[maxn * 2 ]; int head[maxn]; int cnt ; i64 ans ; i64 sum ; i64 sz[maxn]; i64 n ; void init() { memset(head,-1,sizeof(head)); cnt = 0 ; } void add(int u,int v) { e[cnt].v = v ; e[cnt].next = head[u]; head[u] = cnt ++ ; return ; } void dfs(int u,int fa) { for(int i = head[u] ;i != -1 ;i = e[i].next) if(e[i].v != fa) { dfs(e[i].v,u); ans = ans + sz[u] * sz[e[i].v]; sz[u] = sz[u] + sz[e[i].v]; } sz[u] ++ ; ans = ans + (n - sz[u]) * (sz[u] - 1); return ; } int main() { int u,v; while(scanf("%I64d",&n)!=EOF) { init(); for(int i = 0; i < n - 1; i ++) { scanf("%d%d",&u,&v); add(u,v); add(v,u); } for(int i = 1 ;i <= n ; i++ ) sz[i] = 0 ; ans = 0 ; dfs(1,0); sum = n * (n - 1) * (n - 2 ) / 6 ; ans = sum - ans ; printf("%I64d ",ans); } return 0; }
最近刷了写树形DP,好像多了呢