bzoj 1123: [POI2008]BLO

来源:互联网 发布:sql注入在线检测 编辑:程序博客网 时间:2024/03/29 06:30

题意:

给一个连通无向图,问删掉i号点后有多少点对不相连。

题解:

双连通分量的例题。
首先至少有2*(n-1)(删掉的点也算入点对)
非割点就是这样
考虑割点
因为点双缩点后一定是一棵树,所以可以在树上计数。
我是这么做的,分别计算下所有点双中的点数的和,割点的度数和,还有割点的个数,那么就可以得出一个子树不同的点的个数(可能此方法很sb
然后就可以计数了。

update:实际上就是最傻逼的打法

其实直接在tarjan的时候乘就可以了,建议看hzwer的。
code:

#include<cstdlib>#include<cstring>#include<cstdio>#include<iostream>#include<algorithm>#include<vector>#define LL long longusing namespace std;struct node{    int y,next;}A[1000010],a[400010];int Len=0,Last[100010],len=0,last[200010];vector<int> V[1000010];int low[100010],dfn[100010],sta[100010],id=0,tp=0,cnt,num[200010],bel[100010];LL ans[100010];bool v[100010],g[100010];struct trnode{    int g,cnt,num;}tr[200010];void insert(int x,int y){    A[++Len].y=y;    A[Len].next=Last[x];Last[x]=Len;}void ins(int x,int y){    a[++len].y=y;    a[len].next=last[x];last[x]=len;}int n,m;void dfs(int x){    dfn[x]=low[x]=++id;    sta[++tp]=x;v[x]=true;    int tot=0;    for(int i=Last[x];i;i=A[i].next)    {        int y=A[i].y;        if(dfn[y]==-1)        {            dfs(y);tot++;            low[x]=min(low[x],low[y]);            if(low[y]==dfn[x])            {                g[x]=true;bel[x]=++cnt;                V[x].push_back(cnt);                num[cnt]=1;                while(sta[tp+1]!=y)                {                    int z=sta[tp];                    if(g[z]) V[z].push_back(cnt);                    bel[z]=cnt;v[z]=false;tp--;                    num[cnt]++;                }            }        }        else if(v[y]) low[x]=min(low[x],dfn[y]);    }    if(x==1&&tot==1) g[x]=false;}int getsum(int x) {return tr[x].num-tr[x].cnt+tr[x].g;}void solve(int x,int fa){    if(x<=n) tr[x].g++;    else tr[x].num=num[x];    for(int i=last[x];i;i=a[i].next)    {        int y=a[i].y;        if(y==fa) continue;        solve(y,x);        tr[x].g+=tr[y].g;tr[x].num+=tr[y].num;        tr[x].cnt+=tr[y].cnt;tr[x].cnt++;    }    int son=getsum(x);    if(x<=n)        for(int i=last[x];i;i=a[i].next)        {            int y=a[i].y;            if(y==fa) continue;            int sum=getsum(y);            ans[x]+=(LL)(sum-1)*(LL)(n-son)*2;            ans[x]+=(LL)(sum-1)*(LL)(son-sum);        }}int main(){    scanf("%d %d",&n,&m);    for(int i=1;i<=m;i++)    {        int x,y;scanf("%d %d",&x,&y);        insert(x,y);insert(y,x);    }    cnt=n;    memset(v,false,sizeof(v));    memset(dfn,-1,sizeof(dfn));    memset(g,false,sizeof(g));    dfs(1);    for(int x=1;x<=n;x++)        if(g[x])            for(int i=0;i<V[x].size();i++) ins(x,V[x][i]),ins(V[x][i],x);    if(g[1]) solve(1,0);    else solve(bel[1],0);    for(int i=1;i<=n;i++)        printf("%lld\n",ans[i]+(LL)(n-1)*2);}
原创粉丝点击