题意:给一棵树的边标上0或1,求以节点i为源点,其它点到i的唯一路径上的1的边数不超过1条的方案数,输出所有i的答案。

思路:令f[i]表示以节点i为源点,只考虑子树i时的方案数,ans[i]为最后答案,fa[i]为i的父亲,则不难得出以下转移方程:

f[i] = ∏(1 + f[v]),v是i的儿子      ans[i] = f[i] * (1 + ans[fa[i]] / (1 + f[i]))

由于除法取模运算的存在,不得不对1+f[i]求逆元,但1+f[i]可能等于MOD,于是这种情况下结果就是错的了,不能用这个公式求。

令g[i] = ans[fa[i]] / (1 + f[i]),注意到g[i]实际上等于∏(1 + f[v]) * g[fa[i]],v是i的兄弟,于是可以增加一个前缀积数组和一个后缀积数组用来得到∏(1 + f[v]),就不难得到g[i]和最后的答案了。

 #pragma comment(linker, "/STACK:10240000,10240000")

 #include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <map>
#include <queue>
#include <deque>
#include <cmath>
#include <vector>
#include <ctime>
#include <cctype>
#include <set>
#include <bitset>
#include <functional>
#include <numeric>
#include <stdexcept>
#include <utility> using namespace std; #define mem0(a) memset(a, 0, sizeof(a))
#define mem_1(a) memset(a, -1, sizeof(a))
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define define_m int m = (l + r) >> 1
#define rep_up0(a, b) for (int a = 0; a < (b); a++)
#define rep_up1(a, b) for (int a = 1; a <= (b); a++)
#define rep_down0(a, b) for (int a = b - 1; a >= 0; a--)
#define rep_down1(a, b) for (int a = b; a > 0; a--)
#define all(a) (a).begin(), (a).end()
#define lowbit(x) ((x) & (-(x)))
#define constructInt5(name, a, b, c, d, e) name(int a = 0, int b = 0, int c = 0, int d = 0, int e = 0): a(a), b(b), c(c), d(d), e(e) {}
#define constructInt4(name, a, b, c, d) name(int a = 0, int b = 0, int c = 0, int d = 0): a(a), b(b), c(c), d(d) {}
#define constructInt3(name, a, b, c) name(int a = 0, int b = 0, int c = 0): a(a), b(b), c(c) {}
#define constructInt2(name, a, b) name(int a = 0, int b = 0): a(a), b(b) {}
#define pchr(a) putchar(a)
#define pstr(a) printf("%s", a)
#define sstr(a) scanf("%s", a)
#define sint(a) scanf("%d", &a)
#define sint2(a, b) scanf("%d%d", &a, &b)
#define sint3(a, b, c) scanf("%d%d%d", &a, &b, &c)
#define pint(a) printf("%d\n", a)
#define test_print1(a) cout << "var1 = " << a << endl
#define test_print2(a, b) cout << "var1 = " << a << ", var2 = " << b << endl
#define test_print3(a, b, c) cout << "var1 = " << a << ", var2 = " << b << ", var3 = " << c << endl
#define mp(a, b) make_pair(a, b)
#define pb(a) push_back(a) typedef long long LL;
typedef pair<int, int> pii;
typedef vector<int> vi; const int dx[] = {, , -, , , , -, -};
const int dy[] = {-, , , , , -, , - };
const int maxn = 2e5 + ;
const int md = 1e9 + ;
const int inf = 1e9 + ;
const LL inf_L = 1e18 + ;
const double pi = acos(-1.0);
const double eps = 1e-; template<class T>T gcd(T a, T b){return b==?a:gcd(b,a%b);}
template<class T>bool max_update(T &a,const T &b){if(b>a){a = b; return true;}return false;}
template<class T>bool min_update(T &a,const T &b){if(b<a){a = b; return true;}return false;}
template<class T>T condition(bool f, T a, T b){return f?a:b;}
template<class T>void copy_arr(T a[], T b[], int n){rep_up0(i,n)a[i]=b[i];}
int make_id(int x, int y, int n) { return x * n + y; } struct Graph {
vector<vector<int> > G;
void clear() { G.clear(); }
void resize(int n) { G.resize(n + ); }
void add(int u, int v) { G[u].push_back(v); }
vector<int> & operator [] (int u) { return G[u]; }
};
Graph G, pre, suf;
int fa[maxn], f[maxn], ans[maxn], id[maxn], g[maxn]; void dfs(int n) {
f[n] = ;
int sz = G[n].size();
rep_up0(i, sz) {
int v = G[n][i];
dfs(v);
f[n] = (LL)f[n] * ( + f[v]) % md;
}
} void getAns(int n) {
int sz = G[n].size();
int fn = fa[n], in = id[n];
pre[n].resize(sz + );
suf[n].resize(sz + );
pre[n][] = suf[n][sz + ] = ;
if (n == ) {
ans[n] = f[n];
g[n] = ;
}
else {
g[n] = ( + (LL)pre[fn][in - ] % md * suf[fn][in + ] % md * g[fn]) % md;
ans[n] = (LL)f[n] * g[n] % md;
}
rep_up0(i, sz) {
int v = G[n][i];
pre[n][i + ] = (LL)pre[n][i] * ( + f[v]) % md;
}
rep_down0(i, sz) {
int v = G[n][i];
suf[n][i + ] = (LL)suf[n][i + ] * ( + f[v])% md;
}
rep_up0(i, sz) {
int v = G[n][i];
getAns(v);
}
} int main() {
//freopen("in.txt", "r", stdin);
int n;
cin >> n;
G.resize(n);
pre.resize(n);
suf.resize(n);
for (int i = ; i <= n; i ++) {
int x;
sint(x);
G.add(x, i);
fa[i] = x;
id[i] = G[x].size();
}
dfs();
getAns();
rep_up1(i, n) printf("%d%c", ans[i], i == n? '\n' : ' ');
return ;
}

[codeforces-543-D div1]树型DP的更多相关文章

  1. Codeforces 23E Tree(树型DP)

    题目链接 Tree $dp[x][i]$表示以x为根的子树中x所属的连通快大小为i的时候 答案最大值 用$dp[x][j]$ * $dp[y][k]$ 来更新$dp[x][j + k]$. (听高手说 ...

  2. Codeforces 581F Zublicanes and Mumocrates(树型DP)

    题目链接  Round 322 Problem F 题意  给定一棵树,保证叶子结点个数为$2$(也就是度数为$1$的结点),现在要把所有的点染色(黑或白) 要求一半叶子结点的颜色为白,一半叶子结点的 ...

  3. Codeforces 149D Coloring Brackets(树型DP)

    题目链接 Coloring Brackets 考虑树型DP.(我参考了Q巨的代码还是略不理解……) 首先在序列的最外面加一对括号.预处理出DFS树. 每个点有9中状态.假设0位不涂色,1为涂红色,2为 ...

  4. 【题解】codeforces 219D Choosing Capital for Treeland 树型dp

    题目描述 Treeland国有n个城市,这n个城市连成了一颗树,有n-1条道路连接了所有城市.每条道路只能单向通行.现在政府需要决定选择哪个城市为首都.假如城市i成为了首都,那么为了使首都能到达任意一 ...

  5. POJ3659 Cell Phone Network(树上最小支配集:树型DP)

    题目求一棵树的最小支配数. 支配集,即把图的点分成两个集合,所有非支配集内的点都和支配集内的某一点相邻. 听说即使是二分图,最小支配集的求解也是还没多项式算法的.而树上求最小支配集树型DP就OK了. ...

  6. POJ 3342 - Party at Hali-Bula 树型DP+最优解唯一性判断

    好久没写树型dp了...以前都是先找到叶子节点.用队列维护来做的...这次学着vector动态数组+DFS回朔的方法..感觉思路更加的清晰... 关于题目的第一问...能邀请到的最多人数..so ea ...

  7. 【XSY1905】【XSY2761】新访问计划 二分 树型DP

    题目描述 给你一棵树,你要从\(1\)号点出发,经过这棵树的每条边至少一次,最后回到\(1\)号点,经过一条边要花费\(w_i\)的时间. 你还可以乘车,从一个点取另一个点,需要花费\(c\)的时间. ...

  8. 洛谷P3354 Riv河流 [IOI2005] 树型dp

    正解:树型dp 解题报告: 传送门! 简要题意:有棵树,每个节点有个权值w,要求选k个节点,最大化∑dis*w,其中如果某个节点到根的路径上选了别的节点,dis指的是到达那个节点的距离 首先这个一看就 ...

  9. 【POJ 3140】 Contestants Division(树型dp)

    id=3140">[POJ 3140] Contestants Division(树型dp) Time Limit: 2000MS   Memory Limit: 65536K Tot ...

随机推荐

  1. Go gRPC进阶-go-grpc-middleware使用(八)

    前言 上篇介绍了gRPC中TLS认证和自定义方法认证,最后还简单介绍了gRPC拦截器的使用.gRPC自身只能设置一个拦截器,所有逻辑都写一起会比较乱.本篇简单介绍go-grpc-middleware的 ...

  2. SMTP发邮件(直接可用)实例

    string file = "邮件测试.txt";//放在Debug下的一个txt文件. MailAddress from = new MailAddress("自己的邮 ...

  3. php---算法和数据结构

    <?php header("content-type:text/html;charset=utf-8"); $arr = array(3,5,8,4,9,6,1,7,2); ...

  4. 2019-2020-1 20199308《Linux内核原理与分析》第三周作业

    <Linux内核分析> 第二章 操作系统是如何工作的 2.1 函数调用堆栈 3个关键性的方法机制(3个法宝) 存储程序计算机 函数调用堆栈机制 中断 堆栈相关的寄存器 ESP:堆栈指针(s ...

  5. [Qt] QlineEdit 限制输入,例如只能输入整数

    要注意validor的作用域,如果超出作用域,则会无效.例如下面的代码,在UI的类的构造函数里.所以要new一个validtor. QIntValidator *intValidator = new ...

  6. Python带你做个愉快的"动森"玩家! (超简单代码)

    最近Switch上的<动物森友会>可谓是炙手可热,它几乎算是任天堂版的<模拟人生>了,它的最新游戏<集合啦!动物森友会>(以下称“动森”)在发售后,取得了不错的媒体 ...

  7. java中的Atomic类

    文章目录 问题背景 Lock 使用Atomic java中的Atomic类 问题背景 在多线程环境中,我们最常遇到的问题就是变量的值进行同步.因为变量需要在多线程中进行共享,所以我们必须需要采用一定的 ...

  8. Shutdown SpringBoot App

    文章目录 Shutdown Endpoint close Application Context 退出SpringApplication 从外部程序kill App Shutdown SpringBo ...

  9. http请求返回的数字代表的含义

    一些常见的状态码为: 200 - 服务器成功返回网页 404 - 请求的网页不存在 503 - 服务器超时 下面提供 HTTP 状态码的完整列表.点击链接可了解详情.您也可以访问 HTTP 状态码上的 ...

  10. Linux系统管理第一二三四章 系统管理 目录和文件管理 安装及管理程序 账号管理

    命令 功能 序号 第一章   cd 切换目录 1 stat 查看文件状态信息 2 cp 复制   -f -i -p -r 3 du 统计磁盘的大小 4 find 精细查找文件和目录 5 help 帮助 ...