[CF1111E] Tree
Posted qrsikno
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF1111E] Tree相关的知识,希望对你有一定的参考价值。
题意很好懂, 就不讲了.
主要问题在Dp方程式, 设(Dp[i][j])表示询问点中前(i)个点分成(j)个联通块的时候的方案数, 那么有:
[
Dp[i][j] = Dp[i - 1][j - 1] + Dp[i - 1][j] * (j - h[i])
]
(h[i])表示一个点到根的链上有多少个询问点.
你发现询问点数很少. 并且是(sum k_i leq balabalal)的形式, 直接上虚树计算(h[i])
时间复杂度(O(nlogn + (sum k) log (sum k) + sum m_i k _i))
Code
#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)
#define clar(a, b) memset((a), (b), sizeof(a))
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define Debug(s) debug("The massage in line %d, Function %s: %s
", __LINE__, __FUNCTION__, s)
typedef long long LL;
typedef long double LD;
int read() {
char ch = getchar();
int x = 0, flag = 1;
for(;!isdigit(ch); ch = getchar()) if(ch == ‘-‘) flag *= -1;
for(;isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
return x * flag;
}
void write(LL x) {
if(x < 0) putchar(‘-‘), x = -x;
if(x >= 10) write(x / 10);
putchar(x % 10 + 48);
}
const int Maxn = 200009, Mod = 1e9 + 7;
struct edge {
int to, nxt;
}g[Maxn << 1];
int n, head[Maxn], e, q;
int fa[Maxn][21], dep[Maxn], Euler_clk, Beg[Maxn], End[Maxn];
void add(int u, int v) { g[++e] = (edge){v, head[u]}, head[u] = e; }
void dfsInit(int u, int pa) {
fa[u][0] = pa, dep[u] = dep[pa] + 1;
rep (i, 1, 20) fa[u][i] = fa[fa[u][i - 1]][i - 1];
Beg[u] = ++Euler_clk;
for (int i = head[u]; ~i; i = g[i].nxt) {
int v = g[i].to;
if (v != pa) dfsInit(v, u);
}
End[u] = ++Euler_clk;
}
void init() {
clar(head, -1);
n = read(), q = read();
rep (i, 1, n - 1) {
int u = read(), v = read();
add(u, v), add(v, u);
}
dfsInit(1, 0);
}
int LCA(int u, int v) {
if (dep[u] < dep[v]) swap(u, v);
drep (i, 20, 0)
if (dep[fa[u][i]] >= dep[v]) u = fa[u][i];
if (u == v) return u;
drep (i, 20, 0)
if (fa[u][i] != fa[v][i])
u = fa[u][i], v = fa[v][i];
return fa[u][0];
}
int dp[309], instack[Maxn];
vector <int> qset, Tmp;
stack <int> s;
vector <pair<int, int> > Fak;
struct Tree {
edge g[Maxn << 1];
int head[Maxn], e, h[Maxn], mark[Maxn], vised[Maxn];
vector <int> ln;
void init() {
if (ln.size() == 0) clar(head, -1);
rep (i, 0, ln.size() - 1)
head[ln[i]] = -1, h[ln[i]] = mark[ln[i]] = vised[ln[i]] = 0;
ln.clear(), e = 0;
}
void add(int u, int v) {
g[++e] = (edge){v, head[u]}, head[u] = e;
if (!vised[u]) ln.push_back(u), vised[u] = 1;
}
void setMark(int u) { mark[u] = 1; }
int getMark(int u) { return h[u] - mark[u]; }
void travel(int u, int pa) {
h[u] = h[pa] + mark[u];
for (int i = head[u]; ~i; i = g[i].nxt) {
int v = g[i].to;
if (v != pa) travel(v, u);
}
}
}lst;
int cmp(int u, int v) {
return (u < 0 ? End[-u] : Beg[u]) < (v < 0 ? End[-v] : Beg[v]);
}
void solve() {
rep (Fake, 1, q) {
qset.clear(), Tmp.clear();
int k = read(), m = read(), r = read();
rep (i, 1, k) {
int u = read();
qset.push_back(u), instack[u] = 1;
Tmp.push_back(u);
}
if (!instack[r]) qset.push_back(r), instack[r] = 1;
sort(qset.begin(), qset.end(), cmp);
rep (i, 1, qset.size() - 1) {
int l = LCA(qset[i - 1], qset[i]);
if (!instack[l]) instack[l] = 1, qset.push_back(l);
}
if (!instack[1]) instack[1] = 1, qset.push_back(1);
rep (i, 0, qset.size() - 1) qset.push_back(-qset[i]);
sort(qset.begin(), qset.end(), cmp);
lst.init();
rep (i, 1, k) lst.setMark(Tmp[i - 1]);
while (!s.empty()) s.pop();
rep (i, 0, qset.size() - 1)
if (qset[i] > 0) s.push(qset[i]);
else {
int u = s.top(); s.pop(); instack[u] = 0;
if (u != 1) lst.add(s.top(), u), lst.add(u, s.top());
}
qset.clear();
lst.travel(r, 0);
int flag = 0;
rep (i, 1, k) flag |= (lst.getMark(Tmp[i - 1]) >= m);
if (flag) {
puts("0");
continue;
}
rep (j, 0, m) dp[j] = 0;
rep (i, 1, k) {
Fak.push_back(make_pair(lst.getMark(Tmp[i - 1]), Tmp[i - 1]));
// printf("%d %d
", lst.getMark(Tmp[i - 1]), Tmp[i - 1]);
}
sort(Fak.begin(), Fak.end());
dp[0] = 1;
rep (j, 1, k)
drep (l, min(j, m), 0)
if (l <= Fak[j - 1].first) dp[l] = 0;
else {
dp[l] = 1ll * dp[l] * (l - Fak[j - 1].first) % Mod;
if (l > 0) dp[l] = (1ll * dp[l] + dp[l - 1]) % Mod;
}
Tmp.clear(), Fak.clear();
LL ans = 0;
rep (i, 1, m) (ans += dp[i]) %= Mod;
printf("%d
", ans);
}
}
int main() {
freopen("CF1111E.in", "r", stdin);
freopen("CF1111E.out", "w", stdout);
init();
solve();
#ifdef Qrsikno
debug("
Running time: %.3lf(s)
", clock() * 1.0 / CLOCKS_PER_SEC);
#endif
return 0;
}
真的蛋疼, 调了一下午的BUG
主要是判断答案不存在返回的时候要把东西一并清空(Line 98),或者直接在开头一并清除.
以上是关于[CF1111E] Tree的主要内容,如果未能解决你的问题,请参考以下文章