Codeforces 1111E Tree 虚树 + dp

直接把 r 加进去建虚树, 考虑虚树上的dp, 我们考虑虚树的dfs序的顺序dp过去。

dp[ i ][ j ]  表示到 i 这个点为止, 分成 j 组有多少种合法方案。

dp[ i ][ j ] = dp[ i - 1 ][ j ] * (j - have[ i ])  + dp[ i - 1 ][ j - 1 ], have[ i ] 表示 i 的祖先中有多少个在a中出现。

#include<bits/stdc++.h>
using namespace std;

const int N = (int)1e5 + 7;
const int mod = (int)1e9 + 7;
const int LOG = 17;

int n, q, k, m, r, cas, a[N];
int depth[N], pa[N][LOG];
int in[N], ot[N], dfs_clock;
int col[N], dp[301];
vector<int> G[N];

void dfs(int u, int fa) {
    in[u] = ++dfs_clock;
    depth[u] = depth[fa] + 1;
    pa[u][0] = fa;
    for(int i = 1; i < LOG; i++) {
        pa[u][i] = pa[pa[u][i - 1]][i - 1];
    }
    for(auto &v : G[u]) {
        if(v == fa) continue;
        dfs(v, u);
    }
    ot[u] = dfs_clock;
}

inline int getLca(int u, int v) {
    if(depth[u] < depth[v]) swap(u, v);
    int d = depth[u] - depth[v];
    for(int i = LOG - 1; i >= 0; i--) {
        if(d >> i & 1) {
            u = pa[u][i];
        }
    }
    if(u == v) return u;
    for(int i = LOG - 1; i >= 0; i--) {
        if(pa[u][i] != pa[v][i]) {
            u = pa[u][i];
            v = pa[v][i];
        }
    }
    return pa[u][0];
}

void go(int u, int fa, int have) {
    if(col[u] == cas) {
        for(int i = m; i >= 0; i--) {
            if(i < have + 1) dp[i] = 0;
            else {
                dp[i] = 1LL * dp[i] * (i - have) % mod + dp[i - 1];
                if(dp[i] >= mod) dp[i] -= mod;
            }
        }
    }
    for(auto &v : G[u]) {
        if(v == fa) continue;
        go(v, u, have + (col[u] == cas));
    }
}

int main() {
    scanf("%d%d", &n, &q);
    for(int i = 1; i < n; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(1, 0);
    for(cas = 1; cas <= q; cas++) {
        vector<int> P;
        scanf("%d%d%d", &k, &m, &r);
        for(int i = 1; i <= k; i++) scanf("%d", &a[i]), col[a[i]] = cas;
        a[++k] = r;
        for(int i = 1; i <= k; i++) P.push_back(a[i]);
        sort(a + 1, a + 1 + k, [&](int x, int y) {return in[x] < in[y];});
        for(int i = 1; i < k; i++) P.push_back(getLca(a[i], a[i + 1]));
        sort(P.begin(), P.end());
        P.erase(unique(P.begin(), P.end()), P.end());
        sort(P.begin(), P.end(), [&](int x, int y) {return in[x] < in[y];});
        for(auto &t : P) G[t].clear();
        vector<int> S;
        for(auto &t : P) {
            while(S.size() && ot[S.back()] < in[t]) S.pop_back();
            if(S.size()) {
                G[S.back()].push_back(t);
                G[t].push_back(S.back());
            }
            S.push_back(t);
        }
        for(int i = 0; i <= m; i++) dp[i] = (i == 0);
        go(r, 0, 0);
        int ans = 0;
        for(int i = 1; i <= m; i++) {
            ans += dp[i];
            if(ans >= mod) ans -= mod;
        }
        printf("%d\n", ans);
    }
    return 0;
}

/**
**/

原文地址:https://www.cnblogs.com/CJLHY/p/11802682.html

时间: 2024-07-30 00:23:48

Codeforces 1111E Tree 虚树 + dp的相关文章

CodeForces - 613D:Kingdom and its Cities(虚树+DP)

Meanwhile, the kingdom of K is getting ready for the marriage of the King's daughter. However, in order not to lose face in front of the relatives, the King should first finish reforms in his kingdom. As the King can not wait for his daughter's marri

HDU-6035:Colorful Tree(虚树+DP)

这里有三道长得像的题: 一:HDU6036: There is a tree with nn nodes, each of which has a type of color represented by an integer, where the color of node ii is cici. The path between each two different nodes is unique, of which we define the value as the number of

bzoj 3572 [Hnoi2014]世界树(虚树+DP)

3572: [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 645  Solved: 362[Submit][Status][Discuss] Description 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持续运转的根本基石.     世界树的形态可以用一个数学模型来描述:世界树中有n个

BZOJ 3572: [Hnoi2014]世界树 [虚树 DP 倍增]

传送门 题意: 一棵树,多次询问,给出$m$个点,求有几个点到给定点最近 写了一晚上... 当然要建虚树了,但是怎么$DP$啊 大爷题解传送门 我们先求出到虚树上某个点最近的关键点 然后枚举所有的边$(f,x)$,讨论一下边上的点的子树应该靠谁更近 倍增求出分界点 注意有些没出现在虚树上的子树 注意讨论的时候只讨论链上的不包括端点,否则$f$的子树会被贡献多次 学到的一些$trick:$ 1.$pair$的妙用 2.不需要建出虚树只要求虚树的$dfs$序(拓扑序)和$fa$就可以$DP$了 注意

Codeforces 23E Tree(树型DP)

题目链接 Tree dp[x][i]表示以x为根的子树中x所属的连通快大小为i的时候 答案最大值 用dp[x][j] * dp[y][k] 来更新dp[x][j + k]. (听高手说这类题的套路其实都差不多) 因为这题输出数据会很大所以用Java-- QAQ 1 import java.util.*; 2 import java.io.*; 3 import java.math.*; 4 5 public class Main{ 6 static final int maxn = 710; 7

CF461B Appleman and Tree (树DP)

CF462D Codeforces Round #263 (Div. 2) D Codeforces Round #263 (Div. 1) B B. Appleman and Tree time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Appleman has a tree with n vertices. Some of t

BZOJ 3611: [Heoi2014]大工程 [虚树 DP]

传送门 题意: 多次询问,求最长链最短链链总长 煞笔$DP$记录$d,c,f,g$ $MD$该死拍了一下午没问题然后交上去就$T$ 然后发现树链剖分写成$size[v]+=size[u]$ 我想知道我随机生成的大数据是怎么跑过去的!!!!!!!! #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using

【Bzoj2286】消耗战(虚树+DP)

Description 题目链接 Solution 在虚树上跑DP即可 Code #include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #define ll long long #define N 250010 using namespace std; const ll Inf=1ll<<60; struct info{int to,nex;ll w;

codeforces 456d (字典树+DP)

题目大意:给定n,表示字符串集合.给定k,表示进行了k次游戏,然后是n个字符串.每局开始,字符串为空串,然后两人轮流在末尾追加字符,保证新的字符串为集合中某字符串的前缀,不能操作者输,新一轮由上一句输的人先手. 思路:00 代表不能控制 01代表败,10代表胜,11代表能输能赢 转自  http://blog.csdn.net/blankcqk/article/details/38459033 附带字典树模版: void insert(){ int len = strlen(s); int no