CF1111E Tree 樹鏈剖分,DP
阿新 • • 發佈:2019-02-04
return eof == 一個 發現 ++ query tree def 就是線段樹上查詢的值\(- 1\)(不算自己)。處理出\(f\)數組之後,發現祖先的\(f\)值一定比子孫的\(f\)值小,那麽直接對\(f\)數組排一邊序就可以DP了。
CF1111E Tree
過年了,洛咕還沒爬這次的題,先放個CF的鏈接吧。
對於每個詢問點\(x\),設它的祖先即不能和它放在同一個集合中的點的個數為\(f[x]\),設\(dp[i][j]\)表示前\(i\)個詢問點放在\(j\)個非空集合中的方案數,註意這裏“前\(i\)個”的意義,這表示會對第\(i\)個點造成影響的點都已被考慮過了,轉移就是\(dp[i][j] = dp[i - 1][j] * (i - f[j]) + dp[i -1][j - 1]\)。
下面的問題就是怎麽處理出\(f\)數組和找出DP的順序。發現\(f\)數組可以直接樹剖:先在線段樹上把所有詢問點更新一遍,然後再查詢每個點到當前根的路徑上詢問點的個數,\(f[x]\)
//written by newbiechd #include <cstdio> #include <cctype> #include <vector> #include <algorithm> #define R register #define I inline #define B 1000000 #define L long long using namespace std; const int N = 100003, yyb = 1e9 + 7; char buf[B], *p1, *p2; I char gc() { return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, B, stdin), p1 == p2) ? EOF : *p1++; } I int rd() { R int f = 0; R char c = gc(); while (c < 48 || c > 57) c = gc(); while (c > 47 && c < 58) f = f * 10 + (c ^ 48), c = gc(); return f; } int a[N], s[N], fa[N], dep[N], siz[N], son[N], dfn[N], top[N], f[N], v[N << 2], n, tim; L dp[N], ans; vector <int> g[N]; void dfs1(int x, int f) { fa[x] = f, dep[x] = dep[f] + 1, siz[x] = 1; for (R int i = 0, y, m = 0; i < s[x]; ++i) if ((y = g[x][i]) ^ f) { dfs1(y, x), siz[x] += siz[y]; if (siz[y] > m) m = siz[y], son[x] = y; } } void dfs2(int x, int t) { dfn[x] = ++tim, top[x] = t; if (son[x]) dfs2(son[x], t); for (R int i = 0, y; i < s[x]; ++i) if ((y = g[x][i]) ^ fa[x] && y ^ son[x]) dfs2(y, y); } void modify(int k, int l, int r, int x, int y) { v[k] += y; if (l == r) return ; R int p = k << 1, q = p | 1, m = l + r >> 1; if (x <= m) modify(p, l, m, x, y); else modify(q, m + 1, r, x, y); } int tquery(int k, int l, int r, int x, int y) { if (x <= l && r <= y) return v[k]; R int p = k << 1, q = p | 1, m = l + r >> 1, o = 0; if (x <= m) o += tquery(p, l, m, x, y); if (m < y) o += tquery(q, m + 1, r, x, y); return o; } int query(int x, int y) { R int o = 0; while (top[x] ^ top[y]) { if (dep[top[x]] < dep[top[y]]) swap(x, y); o += tquery(1, 1, n, dfn[top[x]], dfn[x]), x = fa[top[x]]; } if (dep[x] > dep[y]) swap(x, y); return o + tquery(1, 1, n, dfn[x], dfn[y]); } int main() { R int Q, k, m, rt, i, j, x, y, flag; n = rd(), Q = rd(); for (i = 1; i < n; ++i) x = rd(), y = rd(), g[x].push_back(y), g[y].push_back(x); for (i = 1; i <= n; ++i) s[i] = g[i].size(); dfs1(1, 0), dfs2(1, 1); while (Q--) { k = rd(), m = rd(), rt = rd(), ans = 0, flag = 0; for (i = 1; i <= k; ++i) a[i] = rd(), modify(1, 1, n, dfn[a[i]], 1); for (i = 1; i <= k; ++i) { f[i] = query(a[i], rt) - 1; if (f[i] >= m) flag = 1; } for (i = 1; i <= k; ++i) modify(1, 1, n, dfn[a[i]], -1), dp[i] = 0; if (flag) { printf("0\n"); continue; } sort(f + 1, f + k + 1), dp[0] = 1; for (i = 1; i <= k; ++i) for (j = min(i, m); ~j; --j) { if (j <= f[i]) dp[j] = 0; dp[j] = (dp[j] * (j - f[i]) + dp[j - 1]) % yyb; } for (j = 1; j <= k; ++j) ans = (ans + dp[j]) % yyb; printf("%I64d\n", ans); } return 0; }
CF1111E Tree 樹鏈剖分,DP