[BZOJ1063][NOI2008]道路设计

传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=1063

Sol

这东西怎么长了一脸树链剖分的样子…

把公路视为轻边 发现轻边的数量是log级别的?

dp[i][j][k]表示在节点i,答案为j,这个点向下连[0,1,2]条边的方案数

直接转移即可

#include <bits/stdc++.h>
using namespace std;
long long dp[100005][20][4],P;
int cnt,nex[200005],las[200005],Arrive[200005],fa[200005],N,M;
void jt(int x,int y){
    cnt++;
    nex[cnt]=las[x];
    las[x]=cnt;
    Arrive[cnt]=y;
}
void dfs(int Now,int k,int fa){
    dp[Now][k][0]=1;
    long long t1,t2;
    for (int i=las[Now];i;i=nex[i]){
        int v=Arrive[i];
        if (v!=fa){
            dfs(v,k,Now);
            if (k) t1=(dp[v][k-1][0]+dp[v][k-1][1]+dp[v][k-1][2]);else t1=0;//不向这个儿子建 
            t2=(dp[v][k][0]+dp[v][k][1]);//向这儿子建
            t1=(t1-1)%P+1;
            t2=(t2-1)%P+1;
            dp[Now][k][2]=dp[Now][k][2]*t1+dp[Now][k][1]*t2;
            dp[Now][k][1]=dp[Now][k][0]*t2+dp[Now][k][1]*t1;        
            dp[Now][k][0]=dp[Now][k][0]*t1;
            dp[Now][k][1]=(dp[Now][k][1]-1)%P+1;
            dp[Now][k][0]=(dp[Now][k][0]-1)%P+1;
            dp[Now][k][2]=(dp[Now][k][2]-1)%P+1;
        }
    }
}
int Getfa(int x){
    return (fa[x]==x)?x:fa[x]=Getfa(fa[x]);
}
int main(){
    scanf("%d%d%lld",&N,&M,&P);
    for (int i=1;i<=N;i++)
        fa[i]=i;
    for (int i=1;i<=M;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        jt(x,y);jt(y,x);
        fa[Getfa(x)]=Getfa(y);
    }
    int x=Getfa(1);
    for (int i=2;i<=N;i++){
        if (Getfa(i)!=x){
            puts("-1");
            puts("-1");
            return 0;
        }
    }
    for (int i=0;;i++){
        dfs(1,i,0);
        if (dp[1][i][0]||dp[1][i][1]||dp[1][i][2]){
            printf("%d
",i);
            printf("%lld
",(dp[1][i][0]+dp[1][i][1]+dp[1][i][2])%P);
            return 0;
        }
    }
}
原文地址:https://www.cnblogs.com/si--nian/p/11520367.html