CF1111E Tree

过年了,洛咕还没爬这次的题,先放个CF的链接吧。

补个LG传送门

对于每个询问点\(x\),设它的祖先即不能和它放在同一个集合中的点的个数为\(f[x]\),设\(dp[i][j]\)表示前\(i\)个询问点放在\(j\)个非空集合中的方案数,注意这里“前\(i\)个”的意义,这表示会对第\(i\)个点造成影响的点都已被考虑过了,转移就是\(dp[i][j] = dp[i - 1][j] * (j - f[j]) + dp[i -1][j - 1]\)。

下面的问题就是怎么处理出\(f\)数组和找出DP的顺序。发现\(f\)数组可以直接树剖:先在线段树上把所有询问点更新一遍,然后再查询每个点到当前根的路径上询问点的个数,\(f[x]\)就是线段树上查询的值\(- 1\)(不算自己)。处理出\(f\)数组之后,发现祖先的\(f\)值一定比子孙的\(f\)值小,那么直接对\(f\)数组排一边序就可以DP了。

//written by newbiechd
#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>
#define R register
#define I inline
#define B 1000000
#define L long long
using namespace std;
const int N = 100003, yyb = 1e9 + 7;
char buf[B], *p1, *p2;
I char gc() { return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, B, stdin), p1 == p2) ? EOF : *p1++; }
I int rd() {
R int f = 0;
R char c = gc();
while (c < 48 || c > 57)
c = gc();
while (c > 47 && c < 58)
f = f * 10 + (c ^ 48), c = gc();
return f;
}
int a[N], s[N], fa[N], dep[N], siz[N], son[N], dfn[N], top[N], f[N], v[N << 2], n, tim;
L dp[N], ans;
vector <int> g[N];
void dfs1(int x, int f) {
fa[x] = f, dep[x] = dep[f] + 1, siz[x] = 1;
for (R int i = 0, y, m = 0; i < s[x]; ++i)
if ((y = g[x][i]) ^ f) {
dfs1(y, x), siz[x] += siz[y];
if (siz[y] > m)
m = siz[y], son[x] = y;
}
}
void dfs2(int x, int t) {
dfn[x] = ++tim, top[x] = t;
if (son[x])
dfs2(son[x], t);
for (R int i = 0, y; i < s[x]; ++i)
if ((y = g[x][i]) ^ fa[x] && y ^ son[x])
dfs2(y, y);
}
void modify(int k, int l, int r, int x, int y) {
v[k] += y;
if (l == r)
return ;
R int p = k << 1, q = p | 1, m = l + r >> 1;
if (x <= m)
modify(p, l, m, x, y);
else
modify(q, m + 1, r, x, y);
}
int tquery(int k, int l, int r, int x, int y) {
if (x <= l && r <= y)
return v[k];
R int p = k << 1, q = p | 1, m = l + r >> 1, o = 0;
if (x <= m)
o += tquery(p, l, m, x, y);
if (m < y)
o += tquery(q, m + 1, r, x, y);
return o;
}
int query(int x, int y) {
R int o = 0;
while (top[x] ^ top[y]) {
if (dep[top[x]] < dep[top[y]])
swap(x, y);
o += tquery(1, 1, n, dfn[top[x]], dfn[x]), x = fa[top[x]];
}
if (dep[x] > dep[y])
swap(x, y);
return o + tquery(1, 1, n, dfn[x], dfn[y]);
}
int main() {
R int Q, k, m, rt, i, j, x, y, flag;
n = rd(), Q = rd();
for (i = 1; i < n; ++i)
x = rd(), y = rd(), g[x].push_back(y), g[y].push_back(x);
for (i = 1; i <= n; ++i)
s[i] = g[i].size();
dfs1(1, 0), dfs2(1, 1);
while (Q--) {
k = rd(), m = rd(), rt = rd(), ans = 0, flag = 0;
for (i = 1; i <= k; ++i)
a[i] = rd(), modify(1, 1, n, dfn[a[i]], 1);
for (i = 1; i <= k; ++i) {
f[i] = query(a[i], rt) - 1;
if (f[i] >= m)
flag = 1;
}
for (i = 1; i <= k; ++i)
modify(1, 1, n, dfn[a[i]], -1), dp[i] = 0;
if (flag) {
printf("0\n");
continue;
}
sort(f + 1, f + k + 1), dp[0] = 1;
for (i = 1; i <= k; ++i)
for (j = min(i, m); ~j; --j) {
if (j <= f[i])
dp[j] = 0;
dp[j] = (dp[j] * (j - f[i]) + dp[j - 1]) % yyb;
}
for (j = 1; j <= k; ++j)
ans = (ans + dp[j]) % yyb;
printf("%I64d\n", ans);
}
return 0;
}

CF1111E Tree 树链剖分,DP的更多相关文章

  1. Hdu 5274 Dylans loves tree (树链剖分模板)

    Hdu 5274 Dylans loves tree (树链剖分模板) 题目传送门 #include <queue> #include <cmath> #include < ...

  2. POJ3237 Tree 树链剖分 边权

    POJ3237 Tree 树链剖分 边权 传送门:http://poj.org/problem?id=3237 题意: n个点的,n-1条边 修改单边边权 将a->b的边权取反 查询a-> ...

  3. 4.12 省选模拟赛 LCA on tree 树链剖分 树状数组 分析答案变化量

    LINK:duoxiao OJ LCA on Tree 题目: 一道树链剖分+树状数组的神题. (直接nQ的暴力有50. 其实对于树随机的时候不难想到一个算法 对于x的修改 暴力修改到根. 对于儿子的 ...

  4. Query on a tree——树链剖分整理

    树链剖分整理 树链剖分就是把树拆成一系列链,然后用数据结构对链进行维护. 通常的剖分方法是轻重链剖分,所谓轻重链就是对于节点u的所有子结点v,size[v]最大的v与u的边是重边,其它边是轻边,其中s ...

  5. 【BZOJ-4353】Play with tree 树链剖分

    4353: Play with tree Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 31  Solved: 19[Submit][Status][ ...

  6. SPOJ Query on a tree 树链剖分 水题

    You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...

  7. poj 3237 Tree 树链剖分

    题目链接:http://poj.org/problem?id=3237 You are given a tree with N nodes. The tree’s nodes are numbered ...

  8. Codeforces Round #200 (Div. 1) D Water Tree 树链剖分 or dfs序

    Water Tree 给出一棵树,有三种操作: 1 x:把以x为子树的节点全部置为1 2 x:把x以及他的所有祖先全部置为0 3 x:询问节点x的值 分析: 昨晚看完题,马上想到直接树链剖分,在记录时 ...

  9. poj 3237 Tree 树链剖分+线段树

    Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...

随机推荐

  1. django项目设计

    我们以前是只建立一个项目只建立一个app,如果我们要建立多个app的时候 并且这个app要写很多额视图的函数views内函数,要是建立很多种的时候就会造成很冗杂,不美观  我们未来增强解耦性,就把那个 ...

  2. Mybatis将结果放入map时别名不是驼峰形式

    查询时如果给字段起别名,并且将查询结果映射到一个Map,那么Map的key将是忽略大小写的.映射到一个实体类是没这个问题的. state as addState 从Map中取值时应该:map.get( ...

  3. WinPE ISO制作

    1.安装ADK,然后导出winPE镜像文件和启动文件: 打开 部署和映像工具环境,cd "Windows Preinstallation Environment",运行 copyp ...

  4. Linux 隐藏系统信息

    Linux查看系统信息 [更多参考]https://www.cnblogs.com/ftl1012/p/uname.html Linux隐藏系统信息 查看: cat /etc/issue.net    ...

  5. 微信小程序初始化 operateWXData:fail invalid scope

    初学者开发微信小程序,可以使用云开发来进行微信小程序的开发. 第一次使用开发工具遇到的问题 解决方案:1.找到云开发 2.点击开通,选择合适自己的开发环境: 3.完成后,返回开发工具界面点击项目第一个 ...

  6. python SQLAlchemy复习

    下面的代码主要使用SQLAlchemy的ORM思想实现查询单词的功能: 实现输入一个单词,查询出与输入单词接近的单词以及单词的意思. 主要有以下三步: 1.创建数据表 2.插入数据 3.查询数据 1. ...

  7. cocos2d-x3.0 柱图

    画柱图就是多画几个矩形之后放在一起,这个实现了基本功能还不够完好假设要用到项目中须要自己改动. 原文地址:http://blog.csdn.net/qqmcy/article/details/2598 ...

  8. 【bzoj2693】jzptab 莫比乌斯反演+线性筛

    题目描述 输入 一个正整数T表示数据组数 接下来T行 每行两个正整数 表示N.M 输出 T行 每行一个整数 表示第i组数据的结果 样例输入 1 4 5 样例输出 122 题解 莫比乌斯反演+线性筛 由 ...

  9. Odoo发送短信

    转载请注明原文地址:https://www.cnblogs.com/cnodoo/p/9281581.html 一:阿里云短信服务注册 1:开通短信业务:实名认证的个人用户是免费开通:企业用户需要提供 ...

  10. virtualbox+vagrant学习-4-Vagrantfile-1-简介

    Vagrantfile Vagrantfile的主要功能是描述项目所需的机器类型,以及如何配置和提供这些机器.之所以称为Vagrantfiles,是因为文件的实际文本文件名是Vagrantfile(除 ...