Codeforces 1111E DP + 树状数组 + LCA + dfs序
题意:给你一颗树,有q次询问,每次询问给你若干个点,这些点可以最多分出m组,每组要满足两个条件:1:每组至少一个点,2:组内的点不能是组内其它点的祖先,问这样的分组能有多少个?
思路:https://blog.csdn.net/BUAA_Alchemist/article/details/86765501
代码:
#include <bits/stdc++.h>
#define LL long long
#define lowbit(x) (x & (-x))
using namespace std;
const LL mod = 1000000007;
const int maxn = 100010;
vector<int> G[maxn];
vector<int> a;
int dfn[maxn], sz[maxn], tot, t;
LL dp[maxn][310];
int n;
void add(int x, int y) {
G[x].push_back(y);
G[y].push_back(x);
}
void dfs(int x, int fa) {
dfn[x] = ++tot;
sz[x] = 1;
for (auto y : G[x]) {
if(y == fa) continue;
dfs(y, x);
sz[x] += sz[y];
}
}
queue<int> q;
int dep[maxn], f[maxn][20];
void bfs() {
q.push(1);
dep[1] = 1;
while(q.size()) {
int x = q.front();
q.pop();
for (auto y : G[x]) {
if(dep[y]) continue;
dep[y] = dep[x] + 1;
//dis[y] = dis[x] + 1;
f[y][0] = x;
for (int j = 1; j <= t; j++)
f[y][j] = f[f[y][j - 1]][j - 1];
q.push(y);
}
}
} int lca(int x, int y) {
if(dep[x] > dep[y]) swap(x, y);
for (int i = t; i >= 0; i--)
if(dep[f[y][i]] >= dep[x]) y = f[y][i];
if(x == y) return y;
for (int i = t; i >= 0; i--)
if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
struct BIT {
int c[maxn];
int ask(int x) {
int ans = 0;
for(; x; x -= lowbit(x)) ans += c[x];
return ans;
} void add(int x, int y) {
for(; x <= n; x += lowbit(x)) c[x] += y;
} };
BIT tr;
int h[maxn], vis[maxn];
int main() {
int u, v, T;
scanf("%d%d", &n, &T);
t = (int)(log(n) / log(2)) + 1;
for (int i = 1; i < n; i++) {
scanf("%d%d", &u, &v);
add(u, v);
}
dfs(1, -1);
bfs();
int k, m, r, x;
LL ans = 0;
while(T--) {
scanf("%d%d%d",&k, &m, &r);
ans = 0;
for (int i = 1; i <= k; i++) {
scanf("%d", &x);
vis[x] = 1;
a.push_back(x);
tr.add(dfn[x], 1);
tr.add(dfn[x] + sz[x], -1);
}
for (int i = 0; i < k; i++) {
int LCA = lca(a[i], r);
h[i + 1] = tr.ask(dfn[a[i]]) + tr.ask(dfn[r]) - 2 * tr.ask(dfn[LCA]) + vis[LCA] - 1;
}
sort(h + 1, h + 1 + k);
dp[0][0] = 1;
for (int i = 1; i <= k; i++)
for (int j = 0; j <= min(i, m); j++) {
if(j > 0)
dp[i][j] = (LL)((LL)dp[i - 1][j - 1] + ((LL)dp[i - 1][j] * max(0, j - h[i])) % mod) % mod;
}
for (int i = 1; i <= m; i++)
ans = (ans + dp[k][i]) % mod;
printf("%lld\n", ans);
for (int i = 0; i < k; i++) {
tr.add(dfn[a[i]], -1);
tr.add(dfn[a[i]] + sz[a[i]], 1);
vis[a[i]] = 0;
}
a.clear();
}
}
Codeforces 1111E DP + 树状数组 + LCA + dfs序的更多相关文章
- BZOJ3881[Coci2015]Divljak——AC自动机+树状数组+LCA+dfs序+树链的并
题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...
- BZOJ 3881 [COCI2015]Divljak (Trie图+Fail树+树链的并+树状数组维护dfs序)
题目大意: Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...
- Codeforces 1096F(dp + 树状数组)
题目链接 题意: 对于长度为$n$的排列,在已知一些位的前提下求逆序对的期望 思路: 将答案分为$3$部分 $1.$$-1$与$-1$之间对答案的贡献.由于逆序对考虑的是数字之间的大小关系,故假设$- ...
- (好题)树状数组+离散化+DFS序+离线/莫队 HDOJ 4358 Boring counting
题目传送门 题意:给你一棵树,树上的每个节点都有树值,给m个查询,问以每个点u为根的子树下有多少种权值恰好出现k次. 分析:首先要对权值离散化,然后要将树形转换为线形,配上图:.然后按照右端点从小到大 ...
- 【BZOJ4999】This Problem Is Too Simple! 离线+树状数组+LCA
[BZOJ4999]This Problem Is Too Simple! Description 给您一颗树,每个节点有个初始值. 现在支持以下两种操作: 1. C i x(0<=x<2 ...
- 树形DP+树状数组 HDU 5877 Weak Pair
//树形DP+树状数组 HDU 5877 Weak Pair // 思路:用树状数组每次加k/a[i],每个节点ans+=Sum(a[i]) 表示每次加大于等于a[i]的值 // 这道题要离散化 #i ...
- bzoj 1264 [AHOI2006]基因匹配Match(DP+树状数组)
1264: [AHOI2006]基因匹配Match Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 793 Solved: 503[Submit][S ...
- hdu4605 树状数组+离散化+dfs
Magic Ball Game Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) ...
- 【bzoj2274】[Usaco2011 Feb]Generic Cow Protests dp+树状数组
题目描述 Farmer John's N (1 <= N <= 100,000) cows are lined up in a row andnumbered 1..N. The cows ...
随机推荐
- SQLRecoverableException: I/O Exception: Connection reset
https://stackoverflow.com/questions/6110395/sqlrecoverableexception-i-o-exception-connection-reset T ...
- Sublime Text 3 - there are no packages available for installation 解决方法
解决方法: 1. 下载一个channel_v3.json , 提取码: n2vc 2. 进入以下路径的设置界面 3. 添加代码 , 文件路径以各自下载保存路径为准 ( 重启sublime, 搞定 ! ...
- 表结构转excel
SELECTCOLUMN_NAME 列名,COLUMN_TYPE 数据类型,DATA_TYPE 字段类型,CHARACTER_MAXIMUM_LENGTH 长度,IS_NULLABLE 是否为空,CO ...
- Math.random()详解
Math.random()是令系统随机选取大于等于 0.0 且小于 1.0 的伪随机 double 值,是Java语言常用代码.例如:double a=Math.random()*(3-1)+1,设置 ...
- tp框架基础控制器调用方法
public function indd(){ //调用该控制器下的某个方法 $this ->index(); //跨控制器调用 $k = A("index");// 创建控 ...
- 小程序推送消息(Template)
最近搞小程序模拟推送消息,才发现小程序推送消息接口准备下线. 请注意,小程序模板消息接口将于2020年1月10日下线,开发者可使用订阅消息功能 咱们现在有需求,所以不管下不下,完成再说. 一:”获取a ...
- BZOJ 3622: 已经没有什么好害怕的了(二项式反演)
传送门 解题思路 首先将\(a\),\(b\)排序,然后可以算出\(t(i)\),表示\(a(i)\)比多少个\(b(i)\)大,根据容斥套路,设\(f(k)\)表示恰好有\(k\)个\(a(i)\) ...
- 洛谷 P2522 [HAOI2011]Problem b (莫比乌斯反演+简单容斥)
题目描述 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. 输入输出格式 输入格式: 第一行一个整数 ...
- dubbo-monitor安装
dubbo-monitor安装 cd /opt/tools/ #包目录 tar -C /opt/ -xf dubbo-monitor-simple--assembly.tar.gz cd dubbo- ...
- windows10下安装Mysql 5.6(zip格式安装包)
5.6的安装包是一个zip文件,里面包含了data(有表空间文件和日志文件),bin等文件夹.不同于以往的只需要双击安装.msi就行了.因此,在此记录下安装包是.zip时的安装步骤. 1下载 进htt ...