樹 [虛樹, 動態規劃]



\color{red}{正解部分}

建出以 rr 爲根的 虛樹, 將 關鍵點 按照 虛樹 中的深度排序, 這樣可以保證一個點的祖先全部在其前面,

F[i,j]F[i, j] 表示前 ii 個點, 分爲 jj 組 的 方案數, g[i]g[i] 表示 iirr 的路徑上 關鍵點 的個數,

因爲 ii 的祖先們必定不是在同一個組內,

所以可以這樣轉移: F[i,j]=(ig[ai])×F[i1,j]+F[i1,j1]F[i, j] = (i - g[a_i])\times F[i-1, j] + F[i-1,j-1], 最後 ans=i=1MF[k,i]ans =\sum\limits_{i=1}^M F[k,i] .


\color{red}{實現部分}

#include<bits/stdc++.h>
#define reg register

int read(){
        char c;
        int s = 0, flag = 1;
        while((c=getchar()) && !isdigit(c))
                if(c == '-'){ flag = -1, c = getchar(); break ; }
        while(isdigit(c)) s = s*10 + c-'0', c = getchar();
        return s * flag;
}

const int mod = 1e9 + 7;
const int maxn = 1e5 + 5;

int N;
int K;
int M;
int R;
int K_;
int Q_;
int hs_cnt;
int dfs_tim;
int num0[2];
int a[maxn];
int b[maxn];
int g[maxn];
int Hs[maxn];
int dfn[maxn];
int stk[maxn];
int dep0[maxn];
int F[maxn][305];
int Fk[maxn][20];
int head[2][maxn];

bool vis[maxn];
bool used[maxn];

struct Edge{ int nxt, to; } edge[2][maxn << 1];

void Add(int from, int to, int id){ edge[id][++ num0[id]] = (Edge){ head[id][from], to }; head[id][from] = num0[id]; }

void DFS_0(int k, int fa){ //
        dfn[k] = ++ dfs_tim; dep0[k] = dep0[fa] + 1;
        for(reg int i = 1; i <= 19; i ++) Fk[k][i] = Fk[Fk[k][i-1]][i-1];
        for(reg int i = head[0][k]; i; i = edge[0][i].nxt){ int to = edge[0][i].to; if(to == fa) continue ; Fk[to][0] = k; DFS_0(to, k); }
}

int Lca(int a, int b){ //
        if(dep0[a] < dep0[b]) std::swap(a, b);
        for(reg int i = 19; i >= 0; i --) if(dep0[Fk[a][i]] >= dep0[b]) a = Fk[a][i]; if(a == b) return a;
        for(reg int i = 19; i >= 0; i --) if(Fk[a][i] != Fk[b][i]) a = Fk[a][i], b = Fk[b][i]; return Fk[a][0];
}

bool cmp_1(int a, int b){ return dfn[a] < dfn[b]; }

bool cmp_2(int a, int b){ return g[a] < g[b]; }

int Dis(int u, int v){ return dep0[u] + dep0[v] - 2*dep0[Lca(u, v)]; }

void Build(){
        std::sort(a+1, a+K+1, cmp_1);
        int top = 0; stk[++ top] = 1;
        for(reg int i = 1 + (a[1]==1); i <= K; i ++){
                int u = stk[top], v = a[i];
                int p = Lca(u, v);
                if(!vis[p]) Hs[++ hs_cnt] = p, vis[p] = 1;
                if(p == u) stk[++ top] = v;
                else{
                        while(dep0[stk[top-1]] >= dep0[p] && top >= 2)
                                Add(stk[top-1], stk[top], 1), Add(stk[top], stk[top-1], 1), top --;
                        if(stk[top] != p) Add(p, stk[top], 1), Add(stk[top], p, 1), stk[top] = p;
                        stk[++ top] = v;
                }
        }
        for(reg int i = 1; i <= top; i ++)
                if(i != top) Add(stk[i], stk[i+1], 1), Add(stk[i+1], stk[i], 1);
}

void DFS(int k, int fa){
        g[k] = g[fa] + used[fa];
        for(reg int i = head[1][k]; i; i = edge[1][i].nxt){ int to = edge[1][i].to; if(to == fa) continue ; DFS(to, k); }
}

void Dp(){
        std::sort(b+1, b+K_+1, cmp_2);
        F[0][0] = 1;
        for(reg int i = 1; i <= K_; i ++)
                for(reg int j = 1; j <= M; j ++) F[i][j] = 0;
        for(reg int i = 1; i <= K_; i ++)
                for(reg int j = 1; j <= M; j ++){
                        F[i][j] = F[i-1][j-1]; 
                        if(j > g[b[i]]) F[i][j] = (F[i][j] + 1ll*F[i-1][j]*(j-g[b[i]])%mod) % mod;
                }
        int Ans = 0;
        for(reg int i = 1; i <= M; i ++) Ans = (Ans + F[K_][i]) % mod;
        printf("%d\n", Ans);
}

void Work(){
        K = read(), M = read(), R = read();
        int flag = 0; hs_cnt = 0;
        for(reg int i = 1; i <= K; i ++){
                b[i] = a[i] = read(); 
                used[a[i]] = vis[a[i]] = 1;
                Hs[++ hs_cnt] = a[i]; 
                if(a[i] == R) flag = 1;
        }
        K_ = K;
        if(!flag) a[++ K] = R, Hs[++ hs_cnt] = R, vis[R] = 1;
        Build(); DFS(R, 0); Dp();
        num0[1] = 0; for(reg int i = 1; i <= hs_cnt; i ++) head[1][Hs[i]] = used[Hs[i]] = vis[Hs[i]] = 0;
}

int main(){
        freopen("tree.in", "r", stdin);
        freopen("tree.out", "w", stdout);
        N = read(); Q_ = read();
        for(reg int i = 1; i < N; i ++){ int u = read(), v = read(); Add(u, v, 0), Add(v, u, 0); }
        DFS_0(1, 0); while(Q_ --) Work(); 
        return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章