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. POST请求的forHTTPHeaderField

    POST请求的forHTTPHeaderField 也许你的iOS项目中使用了AFNetworking2.0,或者是ASIHTTPRequest,对于http中POST请求的操作,你用了他们提供的现成 ...

  2. Linux 系统的主机别名文件

    修改主机名文件 # 方式一: 临时生效 hostname 主机名 hostname omc 临时生效 # 方式二: 编辑配置文件[永久生效] vim /etc/sysconfig/network [更 ...

  3. 《C++ Primer Plus》读书笔记之六—函数探幽

    第八章 函数探幽 1.常规函数与内联函数的主要区别不在于编写方式,而在于C++编译器如何将它们组合到程序中. 2.常规函数调用使程序跳到另外一个地址(函数地址),并在函数结束时返回,更详细的的实现过程 ...

  4. [EffectiveC++]item27:尽量少做转型动作

  5. PHP设计模式系列 - 数据访问对象模式

    数据访问对象模式 数据访问对象模式描述了如何创建透明访问数据源的对象. 场景设计 设计一个BaseDao基类,实现数据库操作基本的一些query,insert,update方法 在实际使用的过程中,继 ...

  6. ubuntu 12.04 64位 安装wps

    1.去wps官网下载linux版的软件 http://community.wps.cn/download/ 我这里下载的是Alpha版的kingsoft-office_9.1.0.4280~a12p4 ...

  7. 【bzoj 3252】攻略

    题意 我们想到一个贪心,就是每次找到根路径前缀和最大的一个点,取走这条路径,同时把这条路径上的点权变成\(0\) 正确性显然 进一步发现我们需要从树上选择\(m\)条链使得链的总和最大 于是我们考虑换 ...

  8. [AHOI2005]矿藏编码

    嘟嘟嘟 这道题题面我是看了小半天才懂(太菜了),然后就发现好水啊. 只要维护一个栈,存的是t,代表当前的正方形是2t * 2t的,然后从头开始扫序列,如果遇到2,就把栈顶元素取出来,然后放进去四个t ...

  9. Hive学习之路 (二)Hive安装

    Hive的下载 下载地址http://mirrors.hust.edu.cn/apache/ 选择合适的Hive版本进行下载,进到stable-2文件夹可以看到稳定的2.x的版本是2.3.3 Hive ...

  10. Java基础加强之并发(一)基本概念介绍

    基本概念介绍 进程:它是内存中的一段独立的空间,可以负责当前应用程序的运行.当前这个进程负责调度当前程序中的所有运行细节. 线程:它是位于进程中,负责当前进程中的某个具备独立运行资格的空间. 进程是负 ...