牛客算法周周练14 C Tree

Tree

https://ac.nowcoder.com/acm/contest/6226/C

C Tree

题目地址:

https://ac.nowcoder.com/acm/contest/6226/C

基本思路:

类似换根的思路,我们先只向下考虑,也就是先只考虑子树的情况。

这样我们设表示以为根的子树中联通点集的数量,那么易得如下转移方程:

然后我们要计算每个点里向上那部分点集的贡献设为,考虑换根,以表示当前节点的最终答案,那么易得如下转移方程:

看上去问题已经解决了,可是题目有一个坑,因为答案是要取模的,所以在 时我们不能直接求逆元计算,所以这时候类似于将子树反向一下,再通过之前算子树的方法暴力计算当前节点的就行了。

参考代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
#define IO std::ios::sync_with_stdio(false)
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define per(i, l, r) for (int i = l; i >= r; i--)
#define mset(s, _) memset(s, _, sizeof(s))
#define pb push_back
#define pii pair <int, int>
#define mp(a, b) make_pair(a, b)
#define INF (int)1e18

inline int read() {
  int x = 0, neg = 1; char op = getchar();
  while (!isdigit(op)) { if (op == '-') neg = -1; op = getchar(); }
  while (isdigit(op)) { x = 10 * x + op - '0'; op = getchar(); }
  return neg * x;
}
inline void print(int x) {
  if (x < 0) { putchar('-'); x = -x; }
  if (x >= 10) print(x / 10);
  putchar(x % 10 + '0');
}
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
inline int qsm(int x,int n){
  int res = 1;
  while (n){
    if(n & 1) res = res * x % mod;
    x = x * x % mod;
    n >>= 1;
  }
  return res;
}
int n;
struct Edge{
    int to,next;
}edge[maxn << 1];
int cnt = 0 ,head[maxn];
void add_edge(int u,int v){
  edge[++cnt].next = head[u];
  edge[cnt].to = v;
  head[u] = cnt;
}
int dp[maxn],fa[maxn];
void dfs1(int u,int par){
  dp[u] = 1; fa[u] = par;
  for(int i = head[u] ; i != -1 ;i = edge[i].next) {
    int to = edge[i].to;
    if (par == to) continue;
    dfs1(to,u);
    dp[u] = dp[u]  * (dp[to] + 1) % mod;
  }
}
int memo[maxn],ans[maxn];
void dfs2(int u,int par) {
  if (u != 1) {
    if ((dp[u] + 1) % mod) { // 不为0直接求逆元;
      memo[u] = ans[par] * qsm(dp[u] + 1LL, mod - 2) % mod;
      ans[u] = dp[u] * (1LL + memo[u]) % mod;
    } else {
      //这部分和dfs1里的dp过程是一样的,只是将子树反向了。
      int tmp = memo[par] + 1;
      for (int i = head[par]; i != -1; i = edge[i].next) { 
        int to = edge[i].to;
        if (to != u && to != fa[par]) tmp = tmp * (dp[to] + 1) % mod;
      }
      memo[u] = tmp;
      ans[u] = (tmp + 1) * dp[u] % mod;
    }
  }
  for (int i = head[u]; i != -1; i = edge[i].next) {
    int to = edge[i].to;
    if (to == par) continue;
    dfs2(to,u);
  }
}
signed main() {
  n = read();
  cnt = 0; mset(head,-1);
  rep(i,1,n - 1) {
    int u = read(), v = read();
    add_edge(u, v);
    add_edge(v, u);
  }
  dfs1(1,0);
  ans[1] = dp[1];
  dfs2(1,0);
  rep(i,1,n) printf("%lld\n",ans[i]);
  return 0;
}
全部评论

相关推荐

沉淀一会:**圣经 1.同学你面试评价不错,概率很大,请耐心等待;2.你的排名比较靠前,不要担心,耐心等待;3.问题不大,正在审批,不要着急签其他公司,等等我们!4.预计9月中下旬,安心过节;5.下周会有结果,请耐心等待下;6.可能国庆节前后,一有结果我马上通知你;7.预计10月中旬,再坚持一下;8.正在走流程,就这两天了;9.同学,结果我也不知道,你如果查到了也告诉我一声;10.同学你出线不明朗,建议签其他公司保底!11.同学你找了哪些公司,我也在找工作。
点赞 评论 收藏
分享
3 收藏 评论
分享
牛客网
牛客企业服务