CF1111E Tree 树链剖分,DP
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的更多相关文章
- Hdu 5274 Dylans loves tree (树链剖分模板)
Hdu 5274 Dylans loves tree (树链剖分模板) 题目传送门 #include <queue> #include <cmath> #include < ...
- POJ3237 Tree 树链剖分 边权
POJ3237 Tree 树链剖分 边权 传送门:http://poj.org/problem?id=3237 题意: n个点的,n-1条边 修改单边边权 将a->b的边权取反 查询a-> ...
- 4.12 省选模拟赛 LCA on tree 树链剖分 树状数组 分析答案变化量
LINK:duoxiao OJ LCA on Tree 题目: 一道树链剖分+树状数组的神题. (直接nQ的暴力有50. 其实对于树随机的时候不难想到一个算法 对于x的修改 暴力修改到根. 对于儿子的 ...
- Query on a tree——树链剖分整理
树链剖分整理 树链剖分就是把树拆成一系列链,然后用数据结构对链进行维护. 通常的剖分方法是轻重链剖分,所谓轻重链就是对于节点u的所有子结点v,size[v]最大的v与u的边是重边,其它边是轻边,其中s ...
- 【BZOJ-4353】Play with tree 树链剖分
4353: Play with tree Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 31 Solved: 19[Submit][Status][ ...
- SPOJ Query on a tree 树链剖分 水题
You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...
- poj 3237 Tree 树链剖分
题目链接:http://poj.org/problem?id=3237 You are given a tree with N nodes. The tree’s nodes are numbered ...
- Codeforces Round #200 (Div. 1) D Water Tree 树链剖分 or dfs序
Water Tree 给出一棵树,有三种操作: 1 x:把以x为子树的节点全部置为1 2 x:把x以及他的所有祖先全部置为0 3 x:询问节点x的值 分析: 昨晚看完题,马上想到直接树链剖分,在记录时 ...
- poj 3237 Tree 树链剖分+线段树
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
随机推荐
- 【数据结构】循环队列 C语言实现
"Queue.h" #include "Queue.h" #include <stdio.h> #include <stdlib.h> ...
- 【原创】python web应用性能测试出现的问题以及使用的工具
uwsgi参数设置问题 问题汇总 listen 参数设置过小导致并发上不去 解决办法 更改listen参数, 请先确认linux系统的上限(tcp_max_syn_backlog,somaxconn) ...
- 在远程登陆的主机上通过命令行源码编译安装 GNU M4、autoconf、automake 等程序
由于实验需要,最近获得了一个实验室服务器的账号,平常主要通过 ssh 进行远程登陆进行实验.一方面,远程登录的机器只提供终端界面,一般只通过命令行进行任务操作:另一方面,由于是多人共享服务器,故而个人 ...
- DIV+CSS:如何编写代码才能更有效率
如何编写CSS代码才能更有效率?这是许多网页制作者与开发者都关心的问题.大概没有什么魔法,可以保证一下就把你的样式表缩小到百分之多少,但合理的 CSS 编码与组织技巧,的确能够帮助你的更有效率地写出更 ...
- myFocus 焦点图/轮播插件
最近产品突然就来个需求,要加轮播图,而且是立马要上线,于是乎发现了一个超级简便好用的轮播图插件myFocus,而且myFocus提供很多种风格,可以选择. 这里是使用说明 http://www.chh ...
- ethers.js-6-Low-Level API
Low-Level API These are advanced, low-level API features that should, for most people not be necessa ...
- swoole_table应用类
<?php/* Redis可真能坑爷,原先的设计用redis保存临时数据,可到了实际应用(实际上也就是几十个人同时用),总是出现莫名其妙的问题,最常见的就是读不出数据来,调试了好多天,那问题还是 ...
- 节点和Topic通信
1.简介 对于实时性. 周期性的消息, 使用topic来传输是最佳的选择. topic是一种点对点的单向通信方式, 这里的“点”指的是node, 也就是说node之间可以通过topic方式来传递信息. ...
- launch edge 和 latch edge 延迟
本文转自 http://www.cnblogs.com/inet2012/archive/2012/03/07/2384149.html launch edge和latch edge分别是指一条路径的 ...
- 使用Charles进行移动APP抓包分析
一.简介 Charles是目前最强大最流行的http抓包调试工具,Mac.Unix.Windows各个平台都支持.特别是做APP开发,调试与服务端的通信,Charles是必备工具. 目前Charles ...