zoukankan      html  css  js  c++  java
  • CF1111E Tree

    题意

    给定一大小为 (N) 的树,共有 (Q) 次询问

    (i) 次询问包含了三个数 (k_i,m_i,r_i),接着给定了树上互不相同的 (k_i) 个关键点 (a_{i,1},a_{i,2},a_{i,3}...a_{i,k})。对于第 (i) 次询问,你需要回答当这颗树以 (r_i) 为根时,有多少种方案将这 (k_i) 个点分为至多 (m_i) 组,使得同一组内的任意两个不同弄的结点都不存在祖先关系

    对于第 (k) 次询问,假设你一共将 (k_i) 个点分为了 (p) 组,那么分组的方案需要满足:

    1. 给出的 (k_i) 个点中每个点属于且仅属于 (p) 组中的任意一组
    2. (p) 组中的任意一组非空

    (N leq 10^5,Qleq 10^5,sum k_ileq 10^5)


    解法

    考虑 DP

    把所有关键点按照一定顺序排好,使得点 (i) 的状态被更新当且仅当 (i) 的祖先的状态都已经被更新

    (f[i][j]) 为把前 (i) 个点分为 (j) 组的方案数,那么有以下转移:

    [f[i][j]=f[i-1][j-1]+f[i-1][j] imes max(0, j-g_i) ]

    其中 (g_i) 指的是第 (i) 个点到根节点的路径上的关键点个数(即祖先关键点的个数)

    这个转移实际上是第二类斯特林数的转移,只不过带了一些限制:当前的点不能与其祖先所在的集合合并(显然其祖先互相之间一定也不属于同一集合)

    (g_i) 可以直接用树剖加树状数组维护,现在的问题就是如何安排 DP 转移的顺序了

    发现按照 (g_i) 从小到大的顺序转移也是完全没有问题的:因为祖先的 (g) 一定比儿子的小(不能用 DFS 序的原因是复杂度无法保证)


    代码

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int MAX_N = 1e5 + 10;
    const int mod = 1e9 + 7;
    
    int read();
    void dfs_1(int x);
    void dfs_2(int x, int tp);
    
    int N, Q;
    
    int f[MAX_N][310];
    int fa[MAX_N], sz[MAX_N], top[MAX_N], dep[MAX_N], son[MAX_N], dfn[MAX_N], cnt;
    
    int head[MAX_N], to[MAX_N << 1], nxt[MAX_N << 1], cap;
    
    inline void swap(int& x, int& y) { x ^= y ^= x ^= y; }
    inline void inc(int& x, int y) { (x += y) >= mod ? x -= mod : 0; }
    inline int mul(int x, int y) { return 1LL * x * y % mod; }
    
    inline int min(int x, int y) { return x < y ? x : y; }
    inline int max(int x, int y) { return x > y ? x : y; }
    
    struct BIT {
    	int c[MAX_N];
    	void ins(int x, int v) {
    		for (; x && x <= N; x += x & -x)  c[x] += v;
    	}
    	int query(int x, int res = 0) {
    		for (; x; x -= x & -x)  res += c[x];
    		return res;	
    	}
    } tr;
    
    struct node { 
    	int x, g;	
    	bool operator < (const node& rhs) const { return g < rhs.g; }
    } a[MAX_N];
    
    inline void link(int x, int y) {
    	to[++cap] = y, nxt[cap] = head[x], head[x] = cap;
    	to[++cap] = x, nxt[cap] = head[y], head[y] = cap;
    }
    
    int query(int u, int v) {
    	int res = 0;
    	while (top[u] ^ top[v]) {
    		if (dep[top[u]] < dep[top[v]])  swap(u, v);
    		res += tr.query(dfn[u]) - tr.query(dfn[top[u]] - 1);
    		u = fa[top[u]];
    	}
    	if (dep[u] < dep[v])  swap(u, v);
    	res += tr.query(dfn[u]) - tr.query(dfn[v] - 1);
    	return res - 1;
    }
    
    int main() {
    	
    	N = read(), Q = read();
    	
    	for (int i = 1; i < N; ++i)  link(read(), read());
    	
    	dep[1] = 1;
    	dfs_1(1);
    	dfs_2(1, 1);
    	
    	int k, m, r;
    	while (Q--) {
    		k = read(), m = read(), r = read();
    		for (int i = 1; i <= k; ++i)  tr.ins(dfn[a[i].x = read()], 1);
    		for (int i = 1; i <= k; ++i)  a[i].g = query(a[i].x, r);
    		
    		sort(a + 1, a + k + 1);
    		
    		f[0][0] = 1;
    		for (int i = 1; i <= k; ++i) 
    			for (int j = 1; j <= m; ++j) 
    				inc(f[i][j], (f[i - 1][j - 1] + mul(f[i - 1][j], max(0, j - a[i].g))) % mod);
    		
    		int res = 0;
    		for (int i = 1; i <= m; ++i)  inc(res, f[k][i]);
    		
    		for (int i = 1; i <= k; ++i)  tr.ins(dfn[a[i].x], -1);
    		for (int i = 1; i <= k; ++i)
    			for (int j = 1; j <= m; ++j)  f[i][j] = 0;
    		
    		printf("%d
    ", res);
    	}
    	
    	return 0;
    }
    
    void dfs_1(int x) {
    	sz[x] = 1;
    	for (int i = head[x]; i; i = nxt[i]) 
    		if (to[i] != fa[x]) {
    			fa[to[i]] = x, dep[to[i]] = dep[x] + 1, dfs_1(to[i]), sz[x] += sz[to[i]];
    			if (sz[to[i]] > sz[son[x]])  son[x] = to[i];
    		}
    }
    
    void dfs_2(int x, int tp) {
    	top[x] = tp, dfn[x] = ++cnt;
    	if (son[x]) {
    		dfs_2(son[x], tp);
    		for (int i = head[x]; i; i = nxt[i])
    			if (!dfn[to[i]])  dfs_2(to[i], to[i]);	
    	}
    }
    
    int read() {
    	int x = 0, c = getchar();
    	while (!isdigit(c))  c = getchar();
    	while (isdigit(c))   x = x * 10 + c - 48, c = getchar();
    	return x;	
    }
    
  • 相关阅读:
    可多开窗口,但是不能同一个窗口多标签 keyshot
    AI符号 和 3DS 实例 有点像
    maya 显示 着色
    不懂
    Rhino 图层
    C4D 怎么学了一个多月还什么都不会
    测试音乐文件 wav mp3 mid
    CAD转CDR之类的会断点怎么解决
    javascript
    react脚手架搭建
  • 原文地址:https://www.cnblogs.com/VeniVidiVici/p/11707722.html
Copyright © 2011-2022 走看看