大意: 给定树, 多组询问, 每个询问给出一个点集$S$, 给定$m, r$, 求根为$r$时, $S$的划分数, 满足

  • 每个划分大小不超过$m$
  • 每个划分内不存在一个点是另一个点的祖先

设点$x$的祖先包括x的个数为$f[x]$ (不属于集合S的点不计算), 按$f$排序后, 有转移

$$dp[i][j]=dp[i-1][j-1]+(j-f[i]+1)dp[i-1][j]$$

dp[i][j]为前i个, 划分为j组的方案数

所以讨论一下$r$与$1$的位置关系求出f就行了

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <math.h>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <string.h>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define PER(i,a,n) for(int i=n;i>=a;--i)
#define hr putchar(10)
#define pb push_back
#define lc (o<<1)
#define rc (lc|1)
#define mid ((l+r)>>1)
#define ls lc,l,mid
#define rs rc,mid+1,r
#define x first
#define y second
#define io std::ios::sync_with_stdio(false)
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int P = 1e9+7, INF = 0x3f3f3f3f;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
//head const int N = 1e5+10;
int n, q;
vector<int> g[N];
int top[N], fa[N], dep[N], son[N];
int L[N], R[N], sz[N]; int calc(int x, int y, int f) {
int pre = 0, lca;
while (top[x]!=top[y]) {
if (dep[top[x]]<dep[top[y]]) swap(x,y);
pre = top[x];
x = fa[pre];
}
if (x==y) lca=x;
else lca=dep[x]<dep[y]?x:y;
if (lca!=f) return 0;
if (fa[pre]==f) return pre;
return son[f];
} void dfs(int x, int f, int d) {
L[x]=++*L,sz[x]=1,fa[x]=f,dep[x]=d;
int mx = -1;
for (int y:g[x]) if (y!=f) {
dfs(y,x,d+1),sz[x]+=sz[y];
if (mx<sz[y]) mx=sz[y],son[x]=y;
}
R[x]=*L;
}
void dfs2(int x, int tf) {
top[x]=tf;
if (son[x]) dfs2(son[x],tf);
for (int y:g[x]) if (y!=fa[x]&&y!=son[x]) dfs2(y,y);
}
int c[N];
void add(int x, int v) {
for (; x<=n; x+=x&-x) c[x]+=v;
}
void update(int l, int r, int v) {
add(l,v),add(r+1,-v);
}
int query(int x) {
int r = 0;
for (; x; x^=x&-x) r+=c[x];
return r;
}
struct _ {
int x,c,f;
} a[N];
int dp[N][322]; int main() {
scanf("%d%d", &n, &q);
REP(i,2,n) {
int u, v;
scanf("%d%d", &u, &v);
g[u].pb(v),g[v].pb(u);
}
dfs(1,0,0),dfs2(1,1);
while (q--) {
int k, m, r;
scanf("%d%d%d", &k, &m, &r);
REP(i,1,k) {
scanf("%d", &a[i].x);
if (a[i].x==r) {update(1,n,1);continue;}
a[i].c = calc(a[i].x,r,a[i].x);
if (!a[i].c) update(L[a[i].x],R[a[i].x],1);
else update(1,n,1),update(L[a[i].c],R[a[i].c],-1);
}
REP(i,1,k) a[i].f = query(L[a[i].x]);
sort(a+1,a+1+k,[](_ a,_ b){return a.f<b.f;});
if (a[k].f<=m) {
dp[0][0] = 1;
REP(i,1,k) REP(j,a[i].f,m) {
dp[i][j] = (dp[i-1][j-1]+(ll)(j-a[i].f+1)*dp[i-1][j])%P;
}
ll ans = 0;
REP(i,a[k].f,m) ans+=dp[k][i];
printf("%d\n", int(ans%P));
REP(i,1,k) REP(j,a[i].f,m) dp[i][j]=0;
}
else puts("0");
REP(i,1,k) {
if (a[i].x==r) update(1,n,-1);
else if (!a[i].c) update(L[a[i].x],R[a[i].x],-1);
else update(1,n,-1),update(L[a[i].c],R[a[i].c],1);
}
}
}

Tree CodeForces - 1111E (树,计数,换根)的更多相关文章

  1. Water Tree CodeForces 343D 树链剖分+线段树

    Water Tree CodeForces 343D 树链剖分+线段树 题意 给定一棵n个n-1条边的树,起初所有节点权值为0. 然后m个操作, 1 x:把x为根的子树的点的权值修改为1: 2 x:把 ...

  2. Codeforces 891D - Sloth(换根 dp)

    Codeforces 题面传送门 & 洛谷题面传送门 换根 dp 好题. 为啥没人做/yiw 首先 \(n\) 为奇数时答案显然为 \(0\),证明显然.接下来我们着重探讨 \(n\) 是偶数 ...

  3. 「BZOJ3083」遥远的国度(树剖换根

    3083: 遥远的国度 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 4859  Solved: 1372[Submit][Status][Discu ...

  4. 2018.10.26 NOIP训练 数数树(换根dp)

    传送门 换根dpdpdp傻逼题好像不好码啊. 考虑直接把每一个二进制位拆开处理. 先dfsdfsdfs出每个点到1的异或距离. 然后分类讨论一波: 如果一个点如果当前二进制位到根节点异或距离为1,那么 ...

  5. 2018.12.19 codeforces 1092F. Tree with Maximum Cost(换根dp)

    传送门 sbsbsb树形dpdpdp题. 题意简述:给出一棵边权为1的树,允许选任意一个点vvv为根,求∑i=1ndist(i,v)∗ai\sum_{i=1}^ndist(i,v)*a_i∑i=1n​ ...

  6. Codeforces Round #527 (Div. 3) F. Tree with Maximum Cost 【DFS换根 || 树形dp】

    传送门:http://codeforces.com/contest/1092/problem/F F. Tree with Maximum Cost time limit per test 2 sec ...

  7. Jamie and Tree CodeForces - 916E (换根)

    大意: n节点树, 每个点有权值, 三种操作: 1,换根. 2, lca(u,v)的子树权值全部增加x. 3, 查询子树权值和. 先不考虑换根, 考虑子树x加v的贡献 (1)对fa[x]到根的树链贡献 ...

  8. Codeforces 1092 F Tree with Maximum Cost (换根 + dfs)

    题意: 给你一棵无根树,每个节点有个权值$a_i$,指定一个点u,定义$\displaystyle value = \sum^v a_i*dist(u,v)$,求value的最大值 n,ai<= ...

  9. [模板] dfs序, 树链剖分, 换根

    树链剖分 树链剖分是一种对树的分治, 可以把树上的任意一条链分解为 \(O(\log n)\) 条在dfs序上相邻的子链, 便于数据结构(如线段树)来维护. 另外, 子树在dfs序上也是一个连续的区间 ...

随机推荐

  1. Java设计模式应用——观察者模式

    告警结果产生后,可能需要发送短信,邮件,故障管理系统.这些转发操作不应当影响告警生成入库,并且类似事件可能根据不同场景,客户习惯不同,此时,使用观察者模式则可以很好的适应上述场景. 观察者模式应当包括 ...

  2. 【tensorflow】pip 安装失败的原因

    linux系统旧版本:   pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.5.0-cp27- ...

  3. Google、亚马逊、微软 、阿里巴巴开源软件一览

    Google.亚马逊.微软 .阿里巴巴开源软件一览 大公司为什么要发布开源项目?一是开源能够帮助他人更快地开发软件,促进世界创新,主要是社会价值层面的考虑.二是开源能够倒逼工程师写出更好的代码.三是开 ...

  4. clock_gettime接口和linux时间系统

    RTC/OSCRTC,Real Time Clock,真实时钟,也叫做CMOS时钟,又叫walltimeOSC,Operation System Clock,系统时钟.在开机时操作系统取得RTC中的时 ...

  5. RPC框架原理剖析(含实例)(转)

    转自:http://blog.csdn.net/rulon147/article/details/53814589 一.什么是RPC RPC(Remote Procedure Call Protoco ...

  6. 热心网友设计出更美的Windows 10开始菜单

    开始菜单应该算是Windows操作系统的标志之一,Win8时微软曾做了大刀阔斧的改革,没想到招致一片负面评价,最终紧急推出了Win8.1系统. Win10推出后,微软等于整合了磁贴和传统风格,但也做不 ...

  7. 干货:Java并发编程必懂知识点解析

    本文大纲 并发编程三要素 原子性 原子,即一个不可再被分割的颗粒.在Java中原子性指的是一个或多个操作要么全部执行成功要么全部执行失败. 有序性 程序执行的顺序按照代码的先后顺序执行.(处理器可能会 ...

  8. 07: linux中正则表达式与grep使用

    1.1 linux中正则表达式 1.^linux        以linux开头的行 2.$php         以php结尾的行 3..                匹配任意单字符 4..+  ...

  9. PHP 开发 api 接口安全验证

    原文链接:http://blog.csdn.net/li741350149/article/details/62887524

  10. 2019“嘉韦思”杯RSA256题目wp

    首先我们从网站下载了一个压缩包,解压出来一看里面有2个文件 首先我们先打开fllllllag康康,结果发现是一串乱码,这时候第一反应就是,文件被加密了,再看fllllllag下面的gy.key文件,更 ...