首页 > 其他分享 >E94 Tarjan边双缩点+树形DP P8867 [NOIP2022] 建造军营

E94 Tarjan边双缩点+树形DP P8867 [NOIP2022] 建造军营

时间:2025-01-06 12:43:52浏览次数:1  
标签:Tarjan int P8867 dfn E94 双缩点 DP low

视频链接:E94 Tarjan边双缩点+树形DP P8867 [NOIP2022] 建造军营_哔哩哔哩_bilibili

 

 

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); //DP
  cout<<ans;
}

 

标签:Tarjan,int,P8867,dfn,E94,双缩点,DP,low
From: https://www.cnblogs.com/dx123/p/18651770

相关文章

  • tarjan 速成
    如题,这是一个只适合快速了解的文章,如果要学习tarjan那么请阅读其他文章。用\(Sub(i)\)表示\(i\)的子树,那么\(low_i\)表示\(Sub(i)\)中的节点和\(Sub(i)\)中的节点经过一条非树边可以到大的节点中\(dfn\)的最小值,用\(dfn_i\)表示\(i\)的时间。从随便一个节点开......
  • LeetCode94二叉树的中序遍历
    原理二叉树的中序遍历遵循“左子树-根节点-右子树”的顺序来访问二叉树中的每个节点。其基本原理是利用递归的思想,先递归地遍历根节点的左子树,访问完左子树的所有节点后,再访问根节点本身,最后递归地遍历根节点的右子树,这样就能按照中序遍历的规则依次访问二叉树中的所有......
  • 模板Tarjan
    Tarjan模板因为每次写Tarjan都会写挂,所以整理了一些模板。主要的证明就跳过了,主要区分不同模板的差异。有向图和无向图有向图和无向图的实现有时候会有区别,因为建出DFS树之后,有向图可能有横叉边,但是无向图不会(显然),所以有些细节需要注意。而且无向图判重边会比较麻烦。无向图......
  • 图论--强连通分量(tarjan)
    一.DFS森林和强连通分量(SCC)强连通:u->v,v->u,那么u和v就是强连通的,即u和v互相可达强连通分量:一个集合内的所有点都互相可达二.tarjan算法#include<bits/stdc++.h>#definexfirst#defineysecond#defineendl'\n'#defineintlonglongusingnamespacestd;......
  • Tarjan详解
    Tarjan算法详解本文介绍利用Tarjan算法求无向图割边、割点、点双连通分量和边双连通分量。一些概念介绍图论相关概念,注意有些概念适用于有向图,但是本文均特指无向图。连通图上两个点至少有一条路径连接,则称两个点连通连通图图上任意两个点都是连通的,则称该图为连通图连通......
  • [题解]P8867 [NOIP2022] 建造军营
    P8867[NOIP2022]建造军营只有B国袭破坏的道路是无向图的割边时,这张图才会变得不连通,所以我们进行边双缩点,最终形成一棵树,不妨令根节点为\(1\)。记\(E[u]\)为缩点后的\(u\)包含多少条原图上的边,\(V[u]\)为\(u\)包含多少个原图上的点,并定义\(s[u]\)表示子树\(u\)中的边数。那么......
  • tarjan[模板]
    强连通分量(有向图)voidtarjan(intx){ dfn[x]=low[x]=++cnt; stac[++top]=x; vis[x]=1; for(inti=hd[x];i;i=nxt[i]) { inty=go[i]; if(!dfn[y])//树边 {tarjan(y);low[x]=min(low[x],low[y]);} elseif(vis[y])low[x]=min(low[x],dfn[y]);//在栈中(判横叉边) }......
  • Tarjan学习笔记
    强连通分量,缩点算法:Tarjan代码及模板强连通图:有向图,任意两点有路径强连通分量:有向图,强连通子图数量前置知识:dfs树(dfs序构成的树)成分:1.树边:dfs树上的边(以下三种边是dfs树上没有但原图上有的边)2.前向边:dfs树的祖先到儿子的边。3.返祖边(后向边):儿子到祖先的边4.横向边:旁系亲......
  • Tarjan
    P3388【模板】割点(割顶)1、注意在遍历时要储存根节点编号,判断时需要特判根节点#include<bits/stdc++.h>usingnamespacestd;constintN=1e5+10;intn,m,r;intdn,dfn[N],low[N],cnt,buc[N];vector<int>e[N];voiddfs(intid){ //标记时间戳 dfn[id]=low[id]......
  • tarjan里的定义
     强连通分量-OIWiki(oi-wiki.org)   从以u为根的子树中的任意点出发。单次到达(从这个点指向某个点,有一条边)的这些点中的dfn的最小值 以v为根的子树,包含在以u为根的子树中,low[v]所用的子节点,一定也可以被low[u],这个点一定在以u为根的子树里,所以用low[v]  从......