\(\mathcal{Description}\)

  Link.

  给定一棵含有 \(n\) 个结点的树,点 \(u\) 有点权 \(w_u\),求树上非空连通块的数量,使得连通块内点权积 \(\le m\)。

  \(n\le2\times10^3\),\(m\le10^6\),\(w_u\in[1,m]\),数据组数 \(T\le10\)。

\(\mathcal{Solution}\)

  很明显是点分,每次考虑跨当前分治重心 \(r\) 的所有连通块对答案的贡献。问题变为:求树上以 \(r\) 为根的满足条件的连通块数量。

  一个简单的想法是以子树为子问题树上 DP,但是点权积的状态空间与子树大小完全无关,子树与子树的合并反而更加浪费时间,这提示我们,应该设计一种仅有单点更新的 DP 状态——以 DFN 为子问题 DP。

  另一方面,由于运算全部是乘法,可以考虑整除分块的储存方式压缩状态树。令 \(f(u,i)\) 表示当 DFS 进行到某一时刻时,以 \(u\) 子树内已经被搜过的点为最大 DFN 点的连通块中,点权积在整除分块后被映射到 \(i\) 的方案数。进入 \(u\) 子树时用 \(u\) 的父亲更新 \(f(u)\),退出 \(u\) 子树时将 \(f(u)\) 上传给 \(u\) 的父亲。设树的大小为 \(s\),DP 的复杂度为 \(\mathcal O(s\sqrt m)\)。

  最终,算法复杂度为 \(\mathcal O(Tn\sqrt m\log n)\)。

\(\mathcal{Code}\)

/*+Rainybunny+*/

#include <bits/stdc++.h>

#define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
#define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i) typedef long long LL; const int MAXN = 2e3, MOD = 1e9 + 7, THRES = 1e3;
int n, m, thres, ecnt, val[MAXN + 5], head[MAXN + 5];
int siz[MAXN + 5], wgt[MAXN + 5], ans;
int f[MAXN + 5][THRES * 2 + 5], g[MAXN + 5][THRES * 2 + 5];
struct Edge { int to, nxt; } graph[MAXN * 2 + 5];
bool vis[MAXN + 5]; inline void chkmax(int& u, const int v) { u < v && (u = v); }
inline int imin(const int u, const int v) { return u < v ? u : v; }
inline void addeq(int& u, const int v) { (u += v) >= MOD && (u -= MOD); } inline void link(const int u, const int v) {
graph[++ecnt] = { v, head[u] }, head[u] = ecnt;
graph[++ecnt] = { u, head[v] }, head[v] = ecnt;
} inline void findG(const int u, const int fa, const int all, int& rt) {
siz[u] = 1, wgt[u] = 0;
for (int i = head[u], v; i; i = graph[i].nxt) {
if (!vis[v = graph[i].to] && v != fa) {
findG(v, u, all, rt), siz[u] += siz[v];
chkmax(wgt[u], siz[v]);
}
}
chkmax(wgt[u], all - siz[u]);
if (!rt || wgt[rt] > wgt[u]) rt = u;
} inline void getDP(const int u, const int fa) {
int *fcur = f[u], *ffa = f[fa];
rep (i, 0, thres << 1) fcur[i] = 0;
if (!fa) fcur[val[u] <= thres ? val[u] : thres + m / val[u]] = 1;
else {
rep (i, 0, imin(thres, m / val[u])) {
int t = i * val[u];
addeq(fcur[t <= thres ? t : thres + m / t], ffa[i]);
}
rep (i, val[u], thres) {
addeq(fcur[thres + i / val[u]], ffa[thres + i]);
}
}
for (int i = head[u], v; i; i = graph[i].nxt) {
if (!vis[v = graph[i].to] && v != fa) {
getDP(v, u);
}
}
if (fa) rep (i, 0, thres << 1) addeq(ffa[i], fcur[i]);
} inline void solve(const int u) {
// printf("!%d\n", u);
vis[u] = true, getDP(u, 0);
rep (i, 0, thres << 1) addeq(ans, f[u][i]);
for (int i = head[u], v, rt; i; i = graph[i].nxt) {
if (!vis[v = graph[i].to]) {
findG(v, 0, siz[v], rt = 0), solve(rt);
}
}
} inline void allClear() {
ans = ecnt = 0;
rep (i, 1, n) head[i] = vis[i] = 0;
} int main() {
int T; scanf("%d", &T);
while (T--) {
scanf("%d %d", &n, &m), thres = int(sqrt(1. * m));
allClear();
rep (i, 1, n) scanf("%d", &val[i]);
rep (i, 2, n) { int u, v; scanf("%d %d", &u, &v), link(u, v); }
int rt = 0; findG(1, 0, n, rt);
solve(rt), printf("%d\n", ans);
}
return 0;
}

Solution -「HDU 6643」Ridiculous Netizens的更多相关文章

  1. Solution -「HDU 6875」Yajilin

    \(\mathcal{Description}\)   Link.(HDU 裂开了先放个私链 awa.)   在一个 \(n\times n\) 的方格图中,格子 \((i,j)\) 有权值 \(w_ ...

  2. Solution -「HDU 5498」Tree

    \(\mathcal{Description}\)   link.   给定一个 \(n\) 个结点 \(m\) 条边的无向图,\(q\) 次操作每次随机选出一条边.问 \(q\) 条边去重后构成生成 ...

  3. Solution -「HDU 1788」CRT again

    \(\mathcal{Description}\)   Link.   解同余方程组: \[x\equiv m_i-a\pmod{m_i} \]   其中 \(i=1,2,\dots,n\).   \ ...

  4. Solution -「HDU #6566」The Hanged Man

    \(\mathcal{Description}\)   Link.   给定一棵含 \(n\) 个点的树,每个结点有两个权值 \(a\) 和 \(b\).对于 \(k\in[1,m]\),分别求 \[ ...

  5. [HDU多校]Ridiculous Netizens

    [HDU多校]Ridiculous Netizens 点分治 分成两个部分:对某一点P,连通块经过P或不经过P. 经过P采用树形依赖背包 不经过P的部分递归计算 树型依赖背包 v点必须由其父亲u点转移 ...

  6. Solution -「ARC 104E」Random LIS

    \(\mathcal{Description}\)   Link.   给定整数序列 \(\{a_n\}\),对于整数序列 \(\{b_n\}\),\(b_i\) 在 \([1,a_i]\) 中等概率 ...

  7. Solution -「HDU」Professor Ben

    Description 有 \(Q\) 个询问.每次给定一个正整数 \(n\),求它的所有因数的质因数个数的和. Solution 就讲中间的一个 Trick. 我们定义正整数 \(x\) 有 \(f ...

  8. Solution -「CTS 2019」「洛谷 P5404」氪金手游

    \(\mathcal{Description}\)   Link.   有 \(n\) 张卡牌,第 \(i\) 张的权值 \(w_i\in\{1,2,3\}\),且取值为 \(k\) 的概率正比于 \ ...

  9. Solution -「BZOJ 3812」主旋律

    \(\mathcal{Description}\)   Link.   给定含 \(n\) 个点 \(m\) 条边的简单有向图 \(G=(V,E)\),求 \(H=(V,E'\subseteq E)\ ...

随机推荐

  1. Centos7 安装LAMP以及nextcloud

    第一步:安装apache 在centos中 apache叫httpd yum update #更新源 yum install httpd #安装apache systemctl stop firewa ...

  2. springboot 配置 swagger2

    1.pom.xml 添加依赖 <!--swagger2 依赖--> <dependency> <groupId>io.springfox</groupId&g ...

  3. react将HTML字符串解析为HTML标签

    当后台返回的数据是字符串html的话,我们可以利用dangerouslySetInnerHTML属性来把字符串转换成html标签 function showhtml(htmlString){ var ...

  4. Nginx虚拟主机、日志排错、模块配置

    目录 Nginx虚拟主机 1. 基于多IP的方式 2. 基于多端口的方式 3. 基于多域名的方式 Nginx日志 Nginx配置文件配置项 Nginx模块 Nginx访问控制模块 Nginx状态监控模 ...

  5. Backbone.js 0.9.2 源码分析收藏

    Backbone 为复杂Javascript应用程序提供模型(models).集合(collections).视图(views)的结构.其中模型用于绑定键值数据和自定义事件:集合附有可枚举函数的丰富A ...

  6. Golang 常见设计模式之选项模式

    熟悉 Python 开发的同学都知道,Python 有默认参数的存在,使得我们在实例化一个对象的时候,可以根据需要来选择性的覆盖某些默认参数,以此来决定如何实例化对象.当一个对象有多个默认参数时,这个 ...

  7. 【Java】二分法查找

    二分法查找 前提:所要查找的数组必须有序 public class Dichotomy { public static void main(String[] args) { int[] array = ...

  8. [爱偷懒的程序员系列]-Section 1. “懒”是一切需求的根源

    一直认为"懒"推进了科技的发展,因为"懒"而促生了各种各样的需求.科技的进步加速了各种信息的交互频率,站在台面上说是因为业务需要提高效率,成本需要降低,服务需要 ...

  9. 微服务架构 | 3.2 Alibaba Nacos 注册中心

    目录 前言 1. Nacos 基础知识 1.1 Nacos 命名方式 1.2 Nasoc 是什么 1.3 Nacos 的 4 个关键特性 1.4 Nacos 生态图 1.5 Nacos 架构图 1.6 ...

  10. 动态多条件mysql模糊查询

    sql拼接函数 public static String Instructor_sql_whole_study(String[] val_ids,String[] val_values) { Stri ...