藍書(演算法競賽進階指南)刷題記錄——BLO
阿新 • • 發佈:2018-12-13
題目大意:給定一張圖,輸出當與點i的相連的邊都被去掉後,有多少個無需點對(x,y)不連通.
這道題其實不難.
首先我們知道,一個點i的所有邊去掉後,這個點i肯定與其它點不相連了,所以不相連的對數先加上n-1.
然後我們發現這個點i若不是割點,那麼對數就只有這麼點.但是如果是割點,我們發現它的獨立子樹(即與點i的父親不在一個聯通塊裡的子樹)與它的父親所在的聯通塊之間會有對數.
我們設一棵獨立子樹的大小為size,則這個獨立子樹會產生的對數為.
而我們設點i父親所在連通塊的大小為size,我們發現會產生的對數也為.
其實藍書上的公式跟這個公式是等價的.
而如何求一棵子樹以j為根是不是獨立子樹?我們只要判斷一棵子樹是否有非樹邊連向點i的父親所在連通塊內的節點,即是否滿足
程式碼如下:
#include<bits/stdc++.h> using namespace std; #define Abigail inline void typedef long long LL; const int N=100000,M=500000; struct side{ int y,next; }e[M*2+9]; struct node{ LL ans; int dfn,low,size; bool cut; }d[N+9]; int n,m,top=1,num,root=1,lin[N+9]; void ins(int X,int Y){ e[++top].y=Y; e[top].next=lin[X]; lin[X]=top; } void tarjan(int k){ int flag=0,size=0; d[k].size=1LL; d[k].ans=LL(n-1); d[k].dfn=d[k].low=++num; for (int i=lin[k];i;i=e[i].next){ int y=e[i].y; if (!d[y].dfn){ tarjan(y); d[k].low=min(d[y].low,d[k].low); d[k].size+=d[y].size; if (d[y].low>=d[k].dfn){ flag++; if (k^root||flag>1) d[k].cut=1; d[k].ans+=1LL*d[y].size*LL(n-d[y].size); }else size+=d[y].size; }else d[k].low=min(d[k].low,d[y].dfn); } size+=LL(n-d[k].size); d[k].ans+=1LL*size*LL(n-size); } Abigail into(){ scanf("%d%d",&n,&m); int x,y; for (int i=1;i<=m;i++){ scanf("%d%d",&x,&y); ins(x,y);ins(y,x); } } Abigail work(){ tarjan(1); } Abigail outo(){ for (int i=1;i<=n;i++) printf("%lld\n",d[i].ans); } int main(){ into(); work(); outo(); return 0; }