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. Fiddler下Firefox提示“您的连接并不安全”的解决办法

    一.版本信息 Firefox 最新版本V46.0.1 Fiddler 最新版本V4.6.2.3 二.错误信息 开启fiddlers的https协议捕获的方法,百度上可以查到不再赘述,直接放张图(Too ...

  2. linux中ftp提示--553 Could not create file

    今天在阿里云的linux上搭建ftp服务的时候,搭建成功之后,上传文件时总提示553 Could not create file,找了半天原因,终于解决了 ftp主目录为/home/myftp /ho ...

  3. Crond定时任务

    crond简介 crond是linux下用来周期性的执行某种任务或等待处理某些事件的一个守护进程,与windows下的计划任务类似,当安装完成操作系统后,默认会安装此服务工具,并且会自动启动crond ...

  4. 【hibernate学习杂记】维护关系的一方和不维护关系的一方的区别与联系

    双向多对一/一对多例子 维护关系一方为User:多方 不维护关系的一方为Group:一方 以下是多方代码: package Hibernate_demo1.Demo8.Entity.OneToMany ...

  5. 【错误记录】python logging日志打印俩次的原因

    有一个原因是因为同一个handler被添加了俩次 applogger = loggerfactory.LoggerFactory.init_app_logger()perflogger = logge ...

  6. python多进程(一)

    操作系统进程 Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊.普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复 ...

  7. debian 7 终端上无法调出输出法

    debian 7 终端konsole上无法调出输出法,无法输入汉字的问题解决方案, export GTK_IM_MODULE=fcitxexport QT_IM_MODULE=fcitxexport ...

  8. Python内置函数.md

    Python3 内置函数 abs(x) 返回一个数的绝对值.参数可以是一个整数或者一个浮点数.如果参数是一个复数,那么将返回它的模. >>> abs(-123456) 123456 ...

  9. 怎样批量提取JPG照片的文件名

    用批处理做吧, @echo off dir /a-d /b >./list.txt 把上面两句代码用记事本保存为“list.bat”(不要引号) 然后把这个文件放到你要提取文件名的文件夹里,就是 ...

  10. IPython学习笔记(一)

    开始看<利用python进行数据分析>这一本书,记录下学习的点滴,对于每一个小知识点记录得过于详细,但是好记性不如烂笔头,动动手还是记得比较深刻点. 1.Tab自动补齐 输入an后按Tab ...