视频链接:
P8867 [NOIP2022] 建造军营 - 洛谷 | 计算机科学教育新生态
// Tarjan边双缩点+树形DP O(n) #include<bits/stdc++.h> using namespace std;int read(){int x=0,f=1;char c=getchar();while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();}while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}return x*f; } const int N=500010,M=2000010,mod=1e9+7; int n,m; int head[N],ne[M],fr[M],to[M],idx=1; void add(int x,int y){fr[++idx]=x;to[idx]=y;ne[idx]=head[x];head[x]=idx; } vector<int> e[N]; stack<int> s; int dfn[N],low[N],tim,dcc[N],sum[N],cnt,bri[M],siz[N]; long long f[N][2],pw[M],ans;void tarjan(int x,int ine){dfn[x]=low[x]=++tim; s.push(x);for(int i=head[x];i;i=ne[i]){int y=to[i];if(!dfn[y]){tarjan(y,i);low[x]=min(low[x],low[y]);if(dfn[x]<low[y]) bri[i]=bri[i^1]=1;}else if(i!=(ine^1))low[x]=min(low[x],dfn[y]);}if(dfn[x]==low[x]){++cnt;while(1){int y=s.top();s.pop();dcc[y]=cnt;++sum[cnt];if(y==x)break;}} } void dfs(int x,int fa){siz[x]=1;f[x][0]=1; f[x][1]=pw[sum[x]]-1;for(int y:e[x]){if(y==fa) continue;dfs(y,x);siz[x]+=siz[y];f[x][1]=(f[x][1]*f[y][0]*2%mod+f[x][1]*f[y][1]%mod+f[x][0]*f[y][1]%mod)%mod;f[x][0]=f[x][0]*f[y][0]*2%mod;}if(x==1) siz[x]--;ans=(ans+f[x][1]*pw[m-siz[x]])%mod; } int main(){n=read();m=read();for(int i=1;i<=m;++i){ //建图int x=read(),y=read();add(x,y);add(y,x);}tarjan(1,0); //缩点for(int i=2;i<=idx;++i) //建树if(bri[i])e[dcc[fr[i]]].push_back(dcc[to[i]]);pw[0]=1;for(int i=1;i<M/2;++i) pw[i]=pw[i-1]*2%mod;dfs(1,0); //DPcout<<ans; }