• Solution 「HDU 6643」Ridiculous Netizens


    \(\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;
    }
    
  • 相关阅读:
    多库查询 sp_addlinkedserver使用方法(添加链接服务器)(转)片段整理
    利用asp.net路由实现url解析
    C#事务 访问数据库(转)
    男人30而立,30岁的男人喊起来!你们立了吗?
    c# 调用SQL Server存储过程返回值(转)
    转摘 JQUERY操作JSON例子
    jstree 从简单说起Jquery 插件应用说明
    利用反射对对象属性赋值取值操作
    asp.net 造成seesion 丢失的问题之一
    jquery 实现从左边listbox选择至右边listbox
  • 原文地址:https://www.cnblogs.com/rainybunny/p/15527885.html
Copyright © 2020-2023  润新知