首页 > 其他分享 >【22NOIP提高组】建造军营(barrack)

【22NOIP提高组】建造军营(barrack)

时间:2023-09-15 17:47:14浏览次数:42  
标签:22NOIP cnt int ll barrack edge low 军营 dp

include<bits/stdc++.h>

using namespace std;

using ll=long long;

const ll M = 1e9+7;

ll fast_pow(ll a,ll b){
ll res = 1;
while(b>0){
if(b&1)res=(resa)%M;;
a=(a
a)%M;
b>>=1;
}
return res;
}

const int N = 6e5+5;

int n,m;
struct Edge{
int u,v;bool flag;
};
vector edges;
vector G[N];

int dfn[N],low[N],dfs_clock;

void tarjan(int u,int fa){
dfn[u]=low[u]=++dfs_clock;
for(int eid:G[u]){
int v = edges[eid].v;
if(!dfn[v]){
tarjan(v,u);
low[u]=min(low[u],low[v]);

        if(low[v]>low[u]){
            edges[eid].flag=1;
            edges[eid^1].flag=1;
        }
    }
    else if(v!=fa){
        low[u]=min(low[u],dfn[v]);
    }
}

}

int vertex_cnt[N],edge_cnt[N];
int fa[N];
int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
void merge(int i,int j){
fa[find(i)]=find(j);
}
vector G2[N];

ll dp[N][2];
ll ans = 0;

ll subtree_edge[N];

void pre(int u,int father){
subtree_edge[u]=edge_cnt[u];
for(int v:G2[u]){
if(v==father)continue;
pre(v,u);
subtree_edge[u]+=subtree_edge[v]+1;
}
}

void dfs(int u,int fand){
bool flag=0;
for(int v:G2[u]){
if(v==fand)continue;
flag=1;
dfs(v,u);
}

// 是叶子节点
if(!flag){
    dp[u][0]=fast_pow(2,edge_cnt[u]);
    dp[u][1]=(fast_pow(2,vertex_cnt[u]))*(dp[u][0])%M;
}
else{
    if(u==fand)
        dp[u][0] = fast_pow(2,edge_cnt[u]+G2[u].size());
    else
        dp[u][0] = fast_pow(2,edge_cnt[u]+G2[u].size()-1);

    
    dp[u][1] = fast_pow(2,vertex_cnt[u]+edge_cnt[u]);
    for(int v:G2[u]){
        if(v==fand)continue;
        dp[u][0] = dp[u][0]*dp[v][0]%M;
        dp[u][1] = dp[u][1]*(2*dp[v][0]+dp[v][1])%M;
    }

}

dp[u][1] = (M+dp[u][1]-dp[u][0])%M;

ans = (ans + dp[u][1]*fast_pow(2,m-subtree_edge[u]-1)%M)%M;

}

int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
int u,v;
scanf("%d%d",&u,&v);
edges.push_back({u,v,0});
edges.push_back({v,u,0});
int cnt = edges.size();
G[u].push_back(cnt-2);
G[v].push_back(cnt-1);
}

// 因为图是连通的,只需要进行一次dfs
tarjan(1,1);

// 建立新图
for(int i=1;i<=n;i++){
    fa[i]=i;
}
for(auto e:edges){
    if(e.flag)continue;
    merge(e.u,e.v);
}
for(auto e:edges){
    int u=find(e.u),v=find(e.v);
    if(u==v){
        edge_cnt[u]++;
    }
    else{
        G2[u].push_back(v);
    }
}

for(int i=1;i<=n;i++){
    edge_cnt[i]/=2;
    vertex_cnt[find(i)]++;
}

pre(fa[1],fa[1]);
dfs(fa[1],fa[1]);    

printf("%lld\n",ans);

return 0;

}

标签:22NOIP,cnt,int,ll,barrack,edge,low,军营,dp
From: https://www.cnblogs.com/boyeyuan/p/17705584.html

相关文章

  • 2022NOIP A层联测35
    好久之前的题了。A.弹珠游戏\(R,G,B\)任意时刻只能出现两种,出现第三种时优先匹配剩下两种的组合,再考虑形成新的组合,匹配啥是一样的,于是每次乘上方案数code#includ......
  • [NOIP2022] 建造军营
    [NOIP2022]建造军营题目描述A国与B国正在激烈交战中,A国打算在自己的国土上建造一些军营。A国的国土由\(n\)座城市组成,\(m\)条双向道路连接这些城市,使得任意两......
  • P8867 NOIP2022 建造军营
    P8867NOIP2022建造军营-洛谷|计算机科学教育新生态(luogu.com.cn)。给定一个无向联通图\(G=(V',E')\),求有多少个二元组\((V,E)\),满足:\(V\subseteqV'\),\(......
  • NOIP2022 T3 建造军营
    只有B国炸毁了图的割边,才会使得图不连通,进而可能会导致军营不连通。也就是说,A国可以随意地看守或不看守不是割边的边。因此想到边双缩点后树形DP。为什么边双缩点后会......
  • P8867 [noip2022]建造军营 题解
    题意:给定一张图,选择一些点和一些边,使得割断任意没有选的边,被选中的点仍连通。对\(10^9+7\)取膜。\(n\leq5\cdot10^5\)这篇题解会略讲缩边,详讲自己推dp状态与......
  • 2022NOIP A层联测35(结局)
    T1:《弹珠游戏》\(n\)个人,\(3n\)个弹珠,分别为\(R,G,B\),每个人三种颜色分别取一个,不满意度为编号极差,求所有人不满意度和最小时的方案数。壮压计数,至于之前每种颜色的......
  • 2022NOIP A层联测34 bs 串 英语作文 计算器 愤怒的小鸟
    T1[图论:并查集维护寻找特殊环]给出一个无向图,点权是0或者1,你可以从任意起点出发,每到达一个点,把这个点的权值放到你构造的字符串的末尾,并且这个点的权值取反。给出K次操作,......
  • 2022NOIPA层联测34
    A.bs串只知道去找环然后挨个判断……正解是把不同色的边连上,枚举哪两个同色的边两端已经联通。二分+并查集。code#include<bits/stdc++.h>usingnamespacestd;......
  • 2022NOIPA层联测33
    C.建筑鹤了才发现我的50pts部分分居然和正解很沾边!!感觉所有序列上说什么用笛卡尔树的东西都可以用单调栈代替,比如《矩形》。50%code/*二缺吧我是,调了俩小时才发现......
  • 2022NOIP A层联测33 GCD 简单题 建筑 树上前缀和
    T1:[图论/枚举]给出有边权无向图,边权保证互不相同,Q次询问从S到T的路径中,边权的gcd最大是多少。(n<=1e4,Q<=2e5,w<=1e6)考场根据之前的一道图论题经验,在最短路上加个“\(w......