边双联通分量

(noip模拟赛)化学竞赛的大奖

(prize.pas/c/cpp)

【问题描述】

XYX 在 CChO(全国化学奥林匹克竞赛)比赛中获得了大奖,奖品是一张特殊的机票。
使用这张机票,可以在任意一个国家内的任意城市之间的免费飞行,只有跨国飞行时才
会有额外的费用。XYX 获得了一张地图,地图上有城市之间的飞机航班和费用。已知从
每个城市出发能到达所有城市,两个城市之间可能有不止一个航班。一个国家内的每两
个城市之间一定有不止一条飞行路线, 而两个国家的城市之间只 有一条飞行路线。 XYX
想知道, 从每个城市出发到额外费用最大的城市, 以便估算出出行的费用, 请你帮助他。
当然,你不能通过乘坐多次一个航班增加额外费用, 也就是必须沿费用最少的路线飞
行。

【输入】

第一行,两个整数 N,M,表示地图上有 N 个城市,M 条航线。
接下来 M 行,每行三个整数 a,b,c,表示城市 a,b 之间有一条费用为 c 的航线。

【输出】

共 N 行,第 i 行为从城市 i 出发到达每个城市额外费用的最大值。

【输入输出样例 1】

输入

6 6 
1 4 2 
1 2 6 
2 5 3 
2 3 7 
6 3 4 
3 1 8

输出






7

有四个国家,包含的城市分别为 {1,2,3},{4},{5},{6}。
从城市 1 出发到达城市 6,乘坐(1,3)(3,6)两个航班费用最大,
(1,3)在国内为免费航班,(3,6)的费用为 4,所以从 1 出发的最
大费用为 4。

【数据范围】

对于 40%的数据 1<=N<=1000,1<=M<=1000
对于 100%的数据 1<=N<=20000,1<=M<=200000

分析

模拟赛的一道题,感觉像tarjan缩点,但这是无向图,

但是思想是一样的,所以写了一个乱搞的tarjan,居然a了。。

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<algorithm>
  4 #include<cstring>
  5
  6 using namespace std;
  7
  8 const int N = 50010;
  9 const int M = 500100;
 10
 11 struct Edge{
 12     int to,w,nxt;
 13     bool flag;
 14     Edge() {flag = false;}
 15 }e[M],t[M];
 16 int head[N],tot = 1,headt[N],tott;
 17 int dfn[N],low[N],st[N],top;
 18 int bel[N],dp[N][3],ans[N];
 19 bool vis[N];
 20 int tn,cnt;
 21
 22 inline int read() {
 23     int x = 0,f =1;char ch = getchar();
 24     for (; ch<‘0‘||ch>‘9‘; ch = getchar())
 25         if (ch==‘-‘) f = -1;
 26     for (; ch>=‘0‘&&ch<=‘9‘; ch = getchar())
 27         x = x*10+ch-‘0‘;
 28     return x*f;
 29 }
 30
 31
 32 void tarjan(int u,int fa) {
 33     dfn[u] = low[u] = ++tn;
 34     st[++top] = u;
 35     vis[u] = true;
 36
 37     for (int i=head[u]; i; i=e[i].nxt) {
 38         int v = e[i].to;
 39         if (!dfn[v]) {
 40             e[i^1].flag = true;
 41             tarjan(v,u);
 42             low[u] = min(low[u],low[v]);
 43         }
 44         else {
 45             if (vis[v] && !e[i].flag) low[u] = min(low[u],dfn[v]);
 46         }
 47     }
 48
 49     if (dfn[u]==low[u]) {
 50         ++cnt;
 51         do {
 52             vis[st[top]] = false;
 53             bel[st[top]] = cnt;
 54             top--;
 55         }while (st[top+1]!=u);
 56     }
 57 }
 58
 59
 60 inline void add_edge(int u,int v,int w) {
 61     t[++tott].to = v,t[tott].w = w,t[tott].nxt = headt[u],headt[u] = tott;
 62     t[++tott].to = u,t[tott].w = w,t[tott].nxt = headt[v],headt[v] = tott;
 63 }
 64
 65 void dfs(int u,int fa) {
 66     int ts = headt[u];
 67     for (int i=headt[u]; i; i=t[i].nxt) {
 68         int v = t[i].to;
 69         if (v==fa) continue;
 70         if (vis[v]) continue;
 71         vis[v] = true;
 72         dfs(v,u);
 73         if (dp[v][0] + t[i].w > dp[u][0]) {
 74             dp[u][1] = dp[u][0];
 75             dp[u][0] = dp[v][0]+t[i].w;
 76         }
 77         else if (dp[v][0]+t[i].w > dp[u][1])
 78             dp[u][1] = dp[v][0]+t[i].w;
 79     }
 80 }
 81 void dfs2(int u,int fa) {
 82
 83     for (int i=headt[u]; i; i=t[i].nxt) {
 84         int v = t[i].to;
 85         if (v==fa) continue;
 86         if (vis[v]) continue;
 87         vis[v] = true;
 88         if (dp[v][0]+t[i].w==dp[u][0])
 89             dp[v][2] = max(dp[u][2],dp[u][1])+t[i].w;
 90         else dp[v][2] = max(dp[u][2],dp[u][0])+t[i].w;
 91         dfs2(v,u);
 92     }
 93 }
 94
 95 int main() {
 96
 97     freopen("prize.in","r",stdin);
 98     freopen("prize.out","w",stdout);
 99
100     int n = read(),m = read();
101     for (int u,v,w,i=1; i<=m; ++i) {
102         u = read(),v = read(),w = read();
103         e[++tot].to = v,e[tot].w = w,e[tot].nxt = head[u],head[u] = tot;
104         e[++tot].to = u,e[tot].w = w,e[tot].nxt = head[v],head[v] = tot;
105     }
106
107     /*for (int i=1; i<=n; ++i)
108         if (!dfn[i]) */
109     tarjan(1,0);
110
111 //    for (int i=1; i<=n; ++i) printf("%d ",bel[i]);
112     for (int i=1; i<=n; ++i)
113         for (int j=head[i]; j; j=e[j].nxt)
114             add_edge(bel[i],bel[e[j].to],e[j].w);
115
116 /*    for (int i=1; i<=4; ++i) {
117         printf("%d",headt[i]);
118     //    for (int j=headt[i]; j; j=t[j].nxt)
119     //        printf("%d ",t[j].to);
120         printf("\n");
121
122     }*/
123     memset(vis,false,sizeof(vis));
124     vis[1] = true;
125     dfs(1,0);
126     memset(vis,false,sizeof(vis));
127     vis[1] = true;
128     dfs2(1,0);
129
130     for (int i=1; i<=cnt; ++i)
131         ans[i] = max(dp[i][0],dp[i][2]);
132
133     for (int i=1; i<=n; ++i)
134         printf("%d\n",ans[bel[i]]);
135     return 0;
136 }
137 /*
138
139 6 6
140 1 4 2
141 1 2 6
142 2 5 3
143 2 3 7
144 6 3 4
145 3 1 8
146
147
148 6 6
149 1 2 1
150 2 3 1
151 2 4 1
152 3 5 1
153 4 5 1
154 5 6 1
155
156 6 7
157 1 2 3
158 2 3 1
159 3 4 1
160 4 5 1
161 2 5 1
162 4 2 1
163 4 6 2
164
165 7 9
166 1 2 3
167 2 3 1
168 3 4 1
169 4 5 1
170 2 5 1
171 4 2 1
172 4 6 2
173 3 7 1
174 4 7 1
175
176 */

后来知道是边双联通分量。。

概念:任意两点至少存在两条边不重复路径

  1 #include<bits/stdc++.h>
  2 #define maxn 20005
  3 #define maxm 200005
  4 using namespace std;
  5
  6 int n,m,id,dfn[maxn],low[maxn],head[maxn],head2[maxn],cnt;
  7 int dis[maxn],dis1[maxn],mx=0,root;
  8 int belong[maxn],belnum;
  9 bool vis[maxn];
 10 stack<int> stk;
 11 struct Edge{
 12 int u,v,val,next;
 13 }edge[maxm<<1],e[maxm<<1];
 14
 15 inline int read()
 16 {
 17     int x=0,f=1;char c=getchar();
 18     while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
 19     while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
 20     return x*f;
 21 }
 22 namespace Tarjan
 23 {
 24
 25 inline void add(int u,int v,int val)
 26 {
 27     edge[++cnt].v=v;
 28     edge[cnt].u=u;
 29     edge[cnt].val=val;
 30     edge[cnt].next=head[u];
 31     head[u]=cnt;
 32 }
 33
 34 inline void tarjan(int u,int fa)
 35 {
 36     dfn[u]=low[u]=++id;
 37     vis[u]=1;
 38     stk.push(u);
 39     for(int i=head[u];i!=-1;i=edge[i].next)
 40     {
 41         int v=edge[i].v;
 42         if(!dfn[v])
 43         {
 44             tarjan(v,u);
 45             low[u]=min(low[u],low[v]);
 46         }
 47         else if(vis[v]&&v!=fa)
 48         {
 49             low[u]=min(low[u],dfn[v]);
 50         }
 51     }
 52     if(dfn[u]==low[u])
 53     {
 54         belnum++;
 55         int temp;
 56         do{
 57             temp=stk.top();
 58             belong[temp]=belnum;
 59             vis[temp]=0;
 60             stk.pop();
 61         }while(temp!=u);
 62     }
 63 }
 64
 65 inline void solve1()
 66 {
 67     memset(head,-1,sizeof(head));
 68     for(int i=1,u,v,val;i<=m;i++)
 69     {
 70         u=read();v=read();val=read();
 71         add(u,v,val);add(v,u,val);
 72     }
 73     for(int i=1;i<=n;i++)
 74     {
 75         if(!dfn[i])    tarjan(i,0);
 76     }
 77 }
 78
 79 }
 80
 81 namespace LP
 82 {
 83
 84 inline void Add(int u,int v,int val)
 85 {
 86     e[++cnt].v=v;
 87     e[cnt].val=val;
 88     e[cnt].next=head2[u];
 89     head2[u]=cnt;
 90 }
 91
 92 void dfs1(int u,int fa)
 93 {
 94     for(int i=head2[u];i!=-1;i=e[i].next)
 95     {
 96         int v=e[i].v;
 97         if(v==fa)    continue;
 98         dis[v]=dis[u]+e[i].val;
 99         if(dis[v]>mx)    mx=dis[v],root=v;
100         dfs1(v,u);
101     }
102 }
103
104 void dfs2(int u,int fa)
105 {
106     for(int i=head2[u];i!=-1;i=e[i].next)
107     {
108         int v=e[i].v;
109         if(v==fa)    continue;
110         dis1[v]=dis1[u]+e[i].val;
111         dfs2(v,u);
112     }
113 }
114
115 inline void solve2()
116 {
117     cnt=0;
118     memset(head2,-1,sizeof(head2));
119     for(int i=1;i<=n;i++)
120         for(int j=head[i];j!=-1;j=edge[j].next)
121         {
122             if(belong[i]!=belong[edge[j].v])
123                 Add(belong[i],belong[edge[j].v],edge[j].val);
124         }
125     dfs1(1,-1);
126     mx=0;memset(dis,0,sizeof(dis));
127     dfs1(root,-1);
128     mx=0;
129     dfs2(root,-1);
130     for(int i=1;i<=n;i++)
131         printf("%d\n",max(dis[belong[i]],dis1[belong[i]]));
132 }
133
134 }
135 int main()
136 {
137     freopen("prize.in","r",stdin);
138     freopen("prize.out","w",stdout);
139     n=read();m=read();
140     Tarjan::solve1();
141     LP::solve2();
142     return 0;
143 }

时间: 2024-10-04 17:07:25

边双联通分量的相关文章

hihocoder #1190 : 连通性&#183;四 点双联通分量

http://hihocoder.com/problemset/problem/1190?sid=1051696 先抄袭一下 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho从约翰家回到学校时,网络所的老师又找到了小Hi和小Ho. 老师告诉小Hi和小Ho:之前的分组出了点问题,当服务器(上次是连接)发生宕机的时候,在同一组的服务器有可能连接不上,所以他们希望重新进行一次分组.这一次老师希望对连接进行分组,并把一个组内的所有连接关联的服务器也视为这个组内

[HDOJ4738]Caocao&#39;s Bridges(双联通分量,割边,tarjan)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4738 给一张无向图,每一条边都有权值.找一条割边,使得删掉这条边双连通分量数量增加,求权值最小那条. 注意有重边,ACEveryDay里群巨给的意见是tarjan的时候记录当前点是从哪条边来的. 注意假如桥的权值是0的时候也得有一个人去炸…… 1 /* 2 ━━━━━┒ギリギリ♂ eye! 3 ┓┏┓┏┓┃キリキリ♂ mind! 4 ┛┗┛┗┛┃\○/ 5 ┓┏┓┏┓┃ / 6 ┛┗┛┗┛┃ノ) 7

UVA - 10765 Doves and bombs (双联通分量)

链接 :  http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=34798 给N个点的无向图并且联通,问删除每次一个点之后还剩多少联通分量. 找割顶 如果删除的是割顶 联通分量就会增加,否则还是1(因为原图是联通图),删除割顶之后 联通块的数目 就要看该割顶在几个双联通分量里出现过. #pragma comment(linker, "/STACK:10240000,10240000") #include <a

【POJ 2942】Knights of the Round Table(双联通分量+染色判奇环)

[POJ 2942]Knights of the Round Table(双联通分量+染色判奇环) Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 11661   Accepted: 3824 Description Being a knight is a very attractive career: searching for the Holy Grail, saving damsels in distress, an

HDU5409---CRB and Graph 2015多校 双联通分量缩点

题意:一个联通的无向图, 对于每一条边, 若删除该边后存在两点不可达,则输出这两个点, 如果存在多个则输出第一个点尽可能大,第二个点尽可能小的. 不存在输出0 0 首先 若删除某一条边后存在多个联通分量则该边一定是桥, 那么我们可以先处理出所有的桥,然后把所有双联通分量缩点,缩点之后就变成了一棵树. 而树上的每一条边都是一个桥, 考虑每条边的输出,删除某一边后肯定会出现两个联通分量, 需要记录两个联通分量中最大的点max1 max2, 如果max1!=n 则答案就是max1 max1+1否则ma

BZOJ2730 矿场搭建 解题报告 点双联通分量

题意概述: 一张有向图,在其中设置一些关键点(即题目中的逃生出口),使得删除任意一个点之后其余点都可以到达至少一个关键点. 问至少需要设置多少中关键点,有多少种设置方法. 解析: 首先,这道题要求删掉一个点,不难想到这道题与割点有关.其次,删掉一个点其他点仍然可以到达关键点就可以想到是点双联通分量. 但是,问题关键是,真的需要在每一个点双联通分量中都设置一个关键点吗? 答案是否定的,因为如果一个双联通分量连接了两个或两个以上的割点,一个割点被删掉那么还可以通过另外的割点到达某个关键点,如上图,红

POJ 1515 双联通分量

点击打开链接 题意:给一个联通的无向图,然后问你将其中的边变为有向的,加边使其变成有向的联通图 思路:若无向图有双联通分量,那么这个分量里的元素可以变成有向图的强联通,这应该很好看出来,然后需要加的边是什么呢,就是这个图上的桥呗,是桥的话变成有向的就要加一条边,然后剩下的无向图的双联通分量可以用dfs搜一下,边搜边输出就可以了,将桥记录下来遇到桥的时候特殊处理一下,然后双联通分量里的边每一条只能走一次,将走得边和反向边标记一下就行了  PS:vector写这样反向边的真是麻烦 #include

HDU 4612 双联通分量+树的直径

点击打开链接 题意:给一个无向联通图,里面可能有重边,问添加一条边后,使得图中的桥最小,将桥的数量输出 思路:刚刚读完题,就有了思路去写,无非就是将联通图双联通分量后缩点,然后求一条最长的路,首尾相连,肯定将更多的桥包含使得这些桥不再是桥,很好想的题,但是错了20+什么鬼,md重边这么难处理,醉了~~~,之前的做法是将重边全部找出来,希望数据弱点水过去算了,TLE好样的,那么我们在处理桥的时候,也就是找桥的时候,如果是桥,我们将这条边标记一下,然后找所有边时加上就行了,在一个就是找树的直径,两次

HDU 4738 Caocao&#39;s Bridges(双联通分量+并查集)

大意:有n座岛和m条桥,每条桥上有w个兵守着,现在要派不少于守桥的士兵数的人去炸桥,只能炸一条桥,使得这n座岛不连通,求最少要派多少人去. 思路:我们就是要缩点后直接求桥上人的最少数量.(PS:1.注意图如果不联通直接输出0.2.如果图中的桥上人为0,个那么要让一个人去.3.重边的问题.这里可以忽略) #include<map> #include<queue> #include<cmath> #include<cstdio> #include<stac

无向图的双联通分量

点双和边双的区别我在上一篇文章中已经讨论过了,这篇文章讲边双的求法. 由于是边双,就决定了边双中一定不含有桥,但是可以含有割顶. 所以我们对边双唯一的限制条件就是不经过桥. 如此一来,我们可以分成两次dfs,第一次求出所有的桥,第二次dfs时遍历整张图,只要保证不经过桥就可以了. #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <s