割点判断+luogu 3469 POI2008 BLO

1.根节点,有2棵及以上子树

2.非根节点,有子节点dfn[u]<=low[v]

#include <bits/stdc++.h>
#define N 1000050
using namespace std;

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}

int head[N],dfn[N],low[N],cut[N];
int cnt,idx;
struct node{int v,next;}e[2*N];
void insert(int u,int v){
    e[++cnt]=(node){v,head[u]};head[u]=cnt;
    e[++cnt]=(node){u,head[v]};head[v]=cnt;
}
void tarjan(int u,int f){
    dfn[u]=low[u]=++idx;
    int rs=0;
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].v;
        if(!dfn[v]){
            tarjan(v,f);rs++;
            low[u]=min(low[u],low[v]);
            if((u==f&&2<=rs)||(u!=f&&dfn[u]<=low[v]))
               cut[u]=1;
        }else
            low[u]=min(low[u],dfn[v]);
    }
}
int n,m,ans;

int main(){
    n=read(),m=read();
    for(int i=1;i<=m;i++){
        int x=read(),y=read();
        insert(x,y);
    }
    for(int i=1;i<=n;i++)
      if(!dfn[i]) tarjan(i,i);
    for(int i=1;i<=n;i++)
      if(cut[i]) ans++;  
    printf("%d\n",ans);
    for(int i=1;i<=n;i++)
      if(cut[i]) printf("%d ",i);
    return 0;
}

 割点+树形dp

在同一连通块内用z累计大小(除u节点)

判断割点并累加内部答案,

最后累加连通块内部与外界答案

树形dp+割点tarjan

#include<bits/stdc++.h>
#define ll long long 
const int N=100050;
const int M=1000050;
using namespace std;

int dfn[N],low[N],siz[N],cut[N];
ll ans[N];
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;}
int head[N],tot,idx,n,m,x,y;
struct node{int v,next;}e[M];
void insert(int u,int v){
    e[++tot]=(node){v,head[u]};head[u]=tot;
    e[++tot]=(node){u,head[v]};head[v]=tot;}
int tarjan(int u){
    int z=0;siz[u]=1;
    dfn[u]=low[u]=++idx;
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].v;
        if(!dfn[v]){
            tarjan(v);
            siz[u]+=siz[v];
            low[u]=min(low[u],low[v]);
            if(dfn[u]<=low[v]){
                ans[u]+=(ll)z*siz[v];
                z+=siz[v];}
                //连通块内部的累加答案 
        }else low[u]=min(low[u],dfn[v]);
    }ans[u]+=(ll)z*(n-z-1);//此连通块内部和外部(除本节点)的累加答案 
}
int main(){
    n=read();m=read();
    for(int i=1;i<=m;i++)
      x=read(),y=read(),insert(x,y);
    tarjan(1);
    for(int i=1;i<=n;i++)
    printf("%lld\n",(ans[i]+n-1)<<1);return 0;
}

 

posted @ 2018-09-05 15:54  ASDIC减除  阅读(93)  评论(0编辑  收藏  举报