洛谷P3469 [POI2008]BLO-Blockade (Tarjan判割点+dfs树切割)

 

题目链接:https://www.luogu.com.cn/problem/P3469

题目解法:

错解(50pts):我先用Tarjan跑了一把找到所有割点,因为非割点的话造成的影响肯定是2*(n-1),所以我们要特殊处理割点的情况。于是呢,我就把割点的相临点全部跑了一把bfs找该组有几个点,然后总点数带来的贡献-各个小组点数带来的贡献和就是最后答案。但是这个复杂度爆了TLE,所以只有50pts

AC解法(100pts):利用tarjan的同时建立dfs树,因为low[v]>=dfn[x]就能判断x是不是割点。在dfs树上会有一些假子节点。而通过刚刚那个判断,我们可以把每一个真子结点进行处理,if(low[v]>=dfn[x]) siz[x]+=siz[v],这个情况就是真子节点因为low[v]和dfn[x]之间 >的情况是是一个单链,而=的情况是一个环。建成真的dfs树后,后面的处理就容易想了。

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
#define eps 0.000000001
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
const int maxn=5e5+5;
int tot,head[maxn];
struct E{
    int to,next;
}edge[maxn<<1];
void add(int u,int v){
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
int n,m;
int id[maxn],dfn[maxn],low[maxn],tott,cnt;
stack<int> s;int fa[maxn],cut[maxn];
vector<int> bccs[maxn];int siz[maxn];ll ans[maxn];
void tarjan(int x){
    low[x]=dfn[x]=++tott;
    s.push(x);int son=0;siz[x]=1;ll sum=0;
    for(int i=head[x];i!=-1;i=edge[i].next){
        int v=edge[i].to;
        if(!dfn[v]){
            ++son;fa[v]=x;
            tarjan(v);siz[x]+=siz[v];
            low[x]=min(low[x],low[v]);
            if(low[v]>=dfn[x]){
                cut[x]=true;
                ans[x]+=1LL*siz[v]*(n-1-siz[v]);        
                sum+=siz[v];
                ++cnt;
                bccs[cnt].clear();
                while(1){
                    int now=s.top();s.pop();
                    id[now]=cnt;
                    bccs[cnt].push_back(now);
                    if(now==v) break;
                }
                id[x]=cnt;
                bccs[cnt].push_back(x);
            }
        }
        else if(v!=fa[x]) low[x]=min(low[x],dfn[v]);
    }
    if(fa[x]==-1&&son==1) cut[x]=false;
    if(!cut[x]) ans[x]=2*(n-1);
    else{
        ans[x]+=1LL*(n-sum-1)*(sum)+2*(n-1);
    }
}
int main(){
    cin>>n>>m;mem(head,-1);
    rep(i,1,m){
        int u,v;cin>>u>>v;
        add(u,v);add(v,u);
    }
    rep(i,1,n){
        if(!dfn[i]){fa[i]=-1;tarjan(i);}
    }
    rep(i,1,n){
        cout<<"TEST "<<dfn[i]<<" "<<low[i]<<endl;
    }
}
View Code

 

posted @ 2020-07-16 22:32  Anonytt  阅读(106)  评论(0编辑  收藏  举报