https://codeforces.com/contest/1111/problem/E

题意

一颗有n个点的树,有q个询问,每次从树挑出k个点,问将这k个点分成m组,需要保证在同一组中不存在一个点是另一个点的祖先这种情况,问有多少中分组方案

题解

  • 首先解决转移问题,假设一次询问全颗树的分组方案数,定义dp[u][i]为到树节点u,分了i组的方案数,其中num(fa[u])为u的祖先节点个数
  • \(dp[u][i]=dp[fa][i]*(i-num(fa[u]))+dp[fa][i-1]\)
    1. 当前这个点独立分组:\(dp[fa][i-1]->dp[u][i]\)
    2. 当前这个点加入前面的分组:\(dp[fa][i]*(i-num(fa[u]))->dp[u][i]\)
  • 反着扫,滚掉一维
  • 然后每次询问一些点,但点询问的总规模数和总点数相同的这种问题可以考虑用虚树解决

代码

#include<bits/stdc++.h>
#define MOD 1000000007
#define MAXN 100005
#define MAXM 305
#define MAXK 100005
#define ll long long
using namespace std;
int n,i,q,u,v,sp[MAXN],dfn[MAXN],dep[MAXN],f[MAXN][40],rt;
ll ans,dp[MAXM];
int k,m,r,ti,S[MAXK];
vector<int>g[MAXN];
vector<int>vt[MAXK]; bool cmp(int x,int y){
return dfn[x]<dfn[y];
}
void dfs1(int u,int fa){
dfn[u]=++ti;
dep[u]=dep[fa]+1;
f[u][0]=fa;
for(int i=1;i<=20;i++)f[u][i]=f[f[u][i-1]][i-1];
for(auto v:g[u])
if(v!=fa)dfs1(v,u);
} int lca(int u,int v){
if(dep[u]<dep[v])swap(u,v);
int dis=dep[u]-dep[v];
for(int i=20;i>=0;i--)if((dis>>i)&1)u=f[u][i];
if(u==v)return u;
for(int i=20;i>=0;i--){
if(f[u][i]!=f[v][i]){
u=f[u][i];
v=f[v][i];
}
}
return f[u][0];
}
void add_edge(int u,int v){
vt[u].push_back(v);
vt[v].push_back(u);
}
void build_vtree(vector<int>& a){
sort(a.begin(),a.end(),cmp);
a.erase(unique(a.begin(),a.end()),a.end());
int t=0;
S[t++]=a[0];
vector<int>b;b.clear();
for(int i=1;i<a.size();i++){
if(t==0){S[t++]=a[i];continue;}
int l=lca(a[i],S[t-1]);
while(t>1&&dfn[S[t-2]]>=dfn[l]){add_edge(S[t-2],S[t-1]);t--;}
if(l!=S[t-1]){add_edge(S[t-1],l);S[t-1]=l;b.push_back(l);}
S[t++]=a[i];
}
while(t>1){add_edge(S[t-1],S[t-2]);t--;}
for(auto u:b)a.push_back(u);
}
void dfs2(int u,int fa,int cnt){
if(sp[u]){
for(int i=m;i>=1;i--){
if(i>cnt)dp[i]=dp[i]*(i-cnt)%MOD;
else dp[i]=0;
dp[i]=(dp[i]+dp[i-1])%MOD;
}
dp[0]=0;
cnt++;
}
for(int i=0;i<vt[u].size();i++){
int v=vt[u][i];if(v==fa)continue;
dfs2(v,u,cnt);
}
} int main(){
cin>>n>>q;
for(int i=0;i<n-1;i++){
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs1(1,0); while(q--){
scanf("%d%d%d",&k,&m,&r);
vector<int>nodes;nodes.clear();
for(int i=0;i<k;i++){
scanf("%d",&u);
nodes.push_back(u);
sp[u]=1;
}
nodes.push_back(r);
build_vtree(nodes);
memset(dp,0,sizeof(dp));
dp[0]=1;
dfs2(r,0,0);
ans=0;
for(int i=0;i<=m;i++)ans=(ans+dp[i])%MOD;
printf("%lld\n",ans);
for(auto u:nodes)sp[u]=0;
for(auto u:nodes)vt[u].clear();
}
}

CodeCraft-19 and Codeforces Round #537 (Div. 2) E 虚树 + 树形dp(新坑)的更多相关文章

  1. Codeforces Round #530 (Div. 2) F 线段树 + 树形dp(自下往上)

    https://codeforces.com/contest/1099/problem/F 题意 一颗n个节点的树上,每个点都有\(x[i]\)个饼干,然后在i节点上吃一个饼干的时间是\(t[i]\) ...

  2. Codeforces Round #536 (Div. 2) F 矩阵快速幂 + bsgs(新坑) + exgcd(新坑) + 欧拉降幂

    https://codeforces.com/contest/1106/problem/F 题意 数列公式为\(f_i=(f^{b_1}_{i-1}*f^{b_2}_{i-2}*...*f^{b_k} ...

  3. Codeforces Round #549 (Div. 2) F 数形结合 + 凸包(新坑)

    https://codeforces.com/contest/1143/problem/F 题意 有n条形如\(y=x^2+bx+c\)的抛物线,问有多少条抛物线上方没有其他抛物线的交点 题解 \(y ...

  4. Codeforces Round #530 (Div. 2)F Cookies (树形dp+线段树)

    题:https://codeforces.com/contest/1099/problem/F 题意:给定一个树,每个节点有俩个信息x和t,分别表示这个节点上的饼干个数和先手吃掉这个节点上一个饼干的的 ...

  5. Codeforces Round #426 (Div. 2) D 线段树优化dp

    D. The Bakery time limit per test 2.5 seconds memory limit per test 256 megabytes input standard inp ...

  6. Codeforces Round #302 (Div. 1) D - Road Improvement 树形dp

    D - Road Improvemen 思路:0没有逆元!!!! 不能直接除,要求前缀积和后缀积!!! #include<bits/stdc++.h> #define LL long lo ...

  7. Codeforces Round #367 (Div. 2) C. Hard problem(DP)

    Hard problem 题目链接: http://codeforces.com/contest/706/problem/C Description Vasiliy is fond of solvin ...

  8. CodeCraft-19 and Codeforces Round #537 Div. 2

    D:即有不超过52种物品,求容量为n/2的有序01背包方案数.容易想到设f[i][j]为前i种物品已用容量为j的方案数,有f[i][j]=f[i-1][j-a[i]]*C(n/2-j+a[i],a[i ...

  9. Codeforces Beta Round #14 (Div. 2) D. Two Paths 树形dp

    D. Two Paths 题目连接: http://codeforces.com/contest/14/problem/D Description As you know, Bob's brother ...

随机推荐

  1. vuex教程,vuex使用介绍案例

    1.demopageaction: import Vue from "vue"; import Store from "../../store.js"; imp ...

  2. tkinter 写一个简易的ide

    简易IDE 基于tkinter的简易ide,参考文档和Baidu的资料制作的,过程中遇到了很多问题,也学到了很多知识. 功能: 1.菜单栏 2.编辑功能 open save... 3.快捷键  ctr ...

  3. 学习excel的使用技巧二批量复制

    1 选中要操作的部分 2 CTRL+G 打开定位 3 点击 定位条件 4 选择空值 5 输入=号  然后键盘的 方向键  向上 6 按住CTRL+回车 即可实现  批量复制

  4. JDK1.7 的 HashMap

    HashMap是一个用于存储key-value的键值对集合,每个键值对都是一个Entry.这些键值对分散存储在一个数组中,这个数组就是HashMap的主干. HashMap每个初始值都为null. 1 ...

  5. Nginx服务器的rewrite、全局变量、重定向和防盗链相关功能

    一:Nginx 后端服务器组的配置: 1.upstream: 用于设置后端服务器组的主要指令,upstream类似于之前的server块或http块,用法如下: upstreame Myserver{ ...

  6. python接收html页面上传的文件

    使用的 flask, 没有安装的先安装 pip install flask 示例代码:示例没有自动创建静态文件夹,需要自己在同级 创建一个名为 static 的文件夹来存放上传的文件 示例展示为图片 ...

  7. python Django 无法获取post 参数问题

    对于 request.POST.get(name) 方式取值,需要 from 表单提交数据,如果 是ajax 提交数据,则需要做如下设置: 1.设置请求头,以from表单方式传值 'Content-T ...

  8. Redux-persist使用

    redux-persist作用是将store中的数据缓存到浏览器中,减少数据请求,每当白名单中的数据发生变化,才会进行一次更新缓存的操作,并且这个数据缓存是存在localStorage中的,不是会话级 ...

  9. 学习node.js 第1篇 介绍nodejs

    Node.js是什么? Node.js是建立在谷歌Chrome的JavaScript引擎(V8引擎)的Web应用程序框架. 它的最新版本是:v0.12.7(在编写本教程时的版本).Node.js在官方 ...

  10. Spring再接触 模拟Spring

    项目分层: 1.最土的方法是直接写到main中去 2.分出model层 2.如下 4.在抽象一个对数据库的访问层(跨数据库实现) 面向抽象编程 User.java package com.bjsxt. ...