3469 [POI2008]BLO-Blockade
洛谷—— P3469 [POI2008]BLO-Blockade
題目描述
There are exactly towns in Byteotia.
Some towns are connected by bidirectional roads.
There are no crossroads outside towns, though there may be bridges, tunnels and flyovers. Each pair of towns may be connected by at most one direct road. One can get from any town to any other-directly or indirectly.
Each town has exactly one citizen.
For that reason the citizens suffer from loneliness.
It turns out that each citizen would like to pay a visit to every other citizen (in his host‘s hometown), and do it exactly once. So exactly ![](
That‘s right, should.
Unfortunately, a general strike of programmers, who demand an emergency purchase of software, is under way.
As an act of protest, the programmers plan to block one town of Byteotia, preventing entering it, leaving it, and even passing through.
As we speak, they are debating which town to choose so that the consequences are most severe.
Task Write a programme that:
reads the Byteotian road system‘s description from the standard input, for each town determines, how many visits could take place if this town were not blocked by programmers, writes out the outcome to the standard output.
給定一張無向圖,求每個點被封鎖之後有多少個有序點對(x,y)(x!=y,1<=x,y<=n)滿足x無法到達y
輸入輸出格式
輸入格式:
In the first line of the standard input there are two positive integers: and (, ) denoting the number of towns and roads, respectively.
The towns are numbered from 1 to .
The following lines contain descriptions of the roads.
Each line contains two integers and () and denotes a direct road between towns numbered and .
輸出格式:
Your programme should write out exactly integers to the standard output, one number per line. The line should contain the number of visits that could not take place if the programmers blocked the town no. .
輸入輸出樣例
輸入樣例#1:5 5 1 2 2 3 1 3 3 4 4 5輸出樣例#1:
8 8 16 14 8
思路:
我們來看一下這道題。
思考一下我們要怎樣做呢??
看到題目:給定一張無向圖,求每個點被封鎖之後有多少個有序點對(x,y)(x!=y,1<=x,y<=n)滿足x無法到達y以後大佬們就應該猜到了這道題的大致做法:圖論。
我們看到樣例以後肯定事先不管他三七二十一,先連起邊來再說。。
但是連完邊以後呢??
有位大佬說:我們連起邊以後先把與這個點直接相連的邊刪掉,然後再判斷有幾塊聯通快,又因為每一塊聯通快內的所有點又都是聯通的,所以每一塊聯通塊所不能到達的就是與他不連通的每一塊的點數,累加就好了,但由於數據太大,我們就要用樹形dp來優化。。。。
但蒟蒻表示並不會樹形dp啊。。。。
哎,無奈只能考慮別的做法了。。。。
我們先來看對於被割掉的這個點來說他所不能到達的點恰好是整張圖上所有的點(除她自己之外(廢話,他肯定能自己到達自己了!!))這樣他所不能聯通的共有:從他出去到所有的點,從所有的點出去到他,也就是說共有:(n-1)*2對。
再就是對於其他的聯通快,我們只需要預處理出每一個點出發到達的點然後再*2就好了。。
又有人要問了:怎樣預處理???!!
我們來樣例來看一下;;
對於割掉點3來說:不能到達的點是這樣來的呢??
割掉點三之後:我們把整張圖分成了這樣三部分:(1,2),(3),(4,5)。
點1不能到達的點就是(1,3)(1,4)(1,5);
點2不能到達的點為(2,3),(2,4,)(2,5)
點3不能到達的點為((3,1),(3,2),(3,4,),(3,5)
點4.。。。。。。。((4,1)(4,2)(4,3)
點5.。。。。。。。(5,1)(5,2)(5,3)
由於我們要*2嘛,所以這個地方我們只能出已成一對的形式
這樣就還剩下(1,3)(1,4)(1,5)(2,3)(2,4)(2,5)(3,4)(3,5)
看看這些,你能發現什麽?!
是不是這樣對於這個圖來說好理解一些
(反掌我是沒太理解。。。)
但是這裏我們可以用別的來做:我們對於一個點出去他所到達的和能到達它的之外。剩下的就是他相連的聯通塊之間的相連的了。
我們在來處理這一部分。在tarjan裏面,我們處理出這個點所能到達且是他的子樹的的聯通塊的大小,這樣他的父親樹的大小就為總點數減去這個點減去他的子樹的大小,即n-1-size[i] i為當前點。 這樣我們又能得知他們之間不能相連的點數就是他的父親節點內的個數*塔子樹節點內的個數、。即ans【i】=t*(n-t-1) t=size[i] 這樣我們求出了從該點外不能互相到達的對數
再加上它能到達的點的對數就是了。不過這裏我們處理出來的是單向到達,我們在輸出時再乘以二就好了!!
代碼:
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define N 100005 #define ll long long using namespace std; int n,m,x,y,tot,tim; int dfn[N],low[N],size[N],head[N],cut_point[N]; ll ans[N]; int read() { int x=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘) {if(ch==‘-‘) f=-1; ch=getchar();} while(ch<=‘9‘&&ch>=‘0‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } struct Edge { int from,next,to; }edge[1000005]; void add(int x,int y) { tot++; edge[tot].to=y; edge[tot].next=head[x]; head[x]=tot; } int tarjan(int now) { int z=0;size[now]=1; dfn[now]=low[now]=++tim; for(int i=head[now];i;i=edge[i].next) { int t=edge[i].to; if(!dfn[t]) { tarjan(t); size[now]+=size[t]; low[now]=min(low[now],low[t]); if(dfn[now]<=low[t]) { ans[now]+=(ll)z*size[t]; z+=size[t]; } } else low[now]=min(low[now],dfn[t]); } ans[now]+=(ll)z*(n-z-1); } int main() { n=read();m=read(); for(int i=1;i<=m;i++) x=read(),y=read(),add(x,y),add(y,x); tarjan(1); for(int i=1;i<=n;i++) printf("%lld\n",(ans[i]+n-1)<<1); return 0; }
3469 [POI2008]BLO-Blockade