码迷,mamicode.com
首页 > 其他好文 > 详细

10.27练习题 [POI2008]Blockade

时间:2019-10-28 19:08:30      阅读:76      评论:0      收藏:0      [点我收藏+]

标签:连通图   ++   不能   块大小   连通   esc   输入   clu   rip   

10.27练习题 [POI2008]Blockade

KONO题面哒!

问题描述
某地区有n个城镇,一些城镇之间由无向边连接。每两个城镇之间至多只有一条直接连接的道路。人们可以从任意一个城镇直接或间接到达另一个城镇。每个城镇都有一个镇长。该地区正在进行镇长互访活动,每个镇长都要拜访其他所有镇长一次。
所以,计划会安排有一共n(n-1)次访问活动。 不幸的是,一个程序员总罢工正在进行中。作为抗议行动,程序员们计划封锁一些城镇,阻止人们进入,离开或者路过那里。他们正在讨论选择哪些城镇会导致最严重的后果。
编写一个程序:计算每个城镇,如果它被封锁,有多少访问活动不会发生,输出结果。
输入格式
第一行读入n,m,分别是城镇数目和道路数目
城镇编号1~n
接下来m行每行两个数字a,b,表示a和b之间有有一条无向边。
输出格式*
输出n行,每行一个数字,为第i个城镇被锁时不能发生的访问活动的数量。

样例输入
5 5
1 2
2 3
1 3
3 4
4 5
样例输出
8
8
16
14
8
数据范围
1≤n≤100000, 1≤m≤500000


你永远也想不到忘了Tarjan算法的绝望
我果然还是太菜了


(割点:即删掉此点原连通图边不连通的点)
把整个地区看成一个联通图,那么封锁一个城镇就相当于把这个点从连通图中删掉。那么,对于被删掉的这个点有两种不同的讨论方式:
(设被删掉的点为x)

  1. x不为割点:则删掉x后原连通图依然连通,所以只有与x号点的访问无法进行。此时答案为2*(n-1)。
  2. x为割点:则删掉x后原连通图将分裂成几个小块,则这几个小块与小块外的点将无法互相访问。所以此时的答案为
    $$\sum^{k}_{i=1}{size[i]*(n-size[i])}$$
    (size[i]表示第i个连通块大小)

注意:求完 x 的子树中所有割点后,还要加上剩下来的大联通块(n?sum?1)×(sum+1)和自己 1×(n?1)次访问。
(由于题面里并没有讲到的整个图联通,所以直接Tarjan(1)就可以了)


KONO代码哒!


#include<iostream> 
#include<cstdio> 
#include<cmath> 
#include<algorithm> 
#define int long long 
using namespace std; 
const int maxn=5000000; 
struct edge { 
    int to,next; 
} g[2*maxn+5]; 
int head[maxn],cnt; 
int n,m; 
int dfn[maxn],low[maxn],size[maxn],Dfn=0; 
int ans[maxn]; 
void add(int from,int to) { 
    g[++cnt].next=head[from]; 
    g[cnt].to=to; 
    head[from]=cnt; 
} 
void T(int x) { 
    dfn[x]=low[x]=++Dfn; 
    int i,j,sum=0; 
    size[x]=1; 
    for(i=head[x]; i; i=g[i].next) { 
        int v=g[i].to; 
        if(!dfn[v]) { 
            T(v); 
            size[x]+=size[v]; 
            low[x]=min(low[x],low[v]); 
            if(dfn[x]<=low[v]) { 
                ans[x]+=sum*size[v]; 
                sum+=size[v]; 
            } 
        } else low[x]=min(low[x],dfn[v]); 
    } 
    ans[x]+=(n-sum-1)*sum; 
    ans[x]+=(n-1); 
} 
main() { 
    ios::sync_with_stdio(0); 
    cin>>n>>m; 
    int i,j; 
    for(i=1; i<=m; i++) { 
        int x,y; 
        cin>>x>>y; 
        add(x,y); 
        add(y,x); 
    } 
    T(1); 
    for(i=1; i<=n; i++) { 
        printf("%lld\n",2LL*ans[i]); 
    } 
    return 0; 
}

(代码写出来奇短……)


今日收获的尼禄!
技术图片

10.27练习题 [POI2008]Blockade

标签:连通图   ++   不能   块大小   连通   esc   输入   clu   rip   

原文地址:https://www.cnblogs.com/cooper233/p/11754212.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!