HDU 5409 CRB and Graph

题意:

给出一个无向图。

问删去每一条边后,是否出现一对(u,v) st 删去这条边后,u和v不连通,且u<v,若有多对,输出u最大的,然后v最小的。

数据范围10^5

 

思路:

首先显然先用tarjan处理处各个强连通块。顺便处理处每个块中的点编号最大的是多少。以belong[x]表示x这个点属于哪个块。

对于一条边,若他不是桥边,则删去他后不会出现不联通的u,v,结果是0 0

如果是桥边,就以(belong[x], belong[y])为边加入新图中

然后我们缩完了点获得了一棵树.

若是桥边:太(wo)巧(tai)妙(chun)惹。

  首先达成共识:若i这个块中,最大的点为maxn[i],则点maxn[i]+1和不在i这个块中。

        同理若以maxn[i]表示i子树上的最大值,则点maxn[i]+1不在这i子树上

  然后处理:

  1.以n所在的块为根,处理这棵树。接下来都把块视为点了因为打字麻烦= =

  2.处理出maxn[i]为i的子树中值得最大值 即 maxn[i] = max{maxn[j] | i 是 j 的祖先},这个可以简单树形DP处理出。顺便处理出每个点的深度。

  3.接下来继续前面的枚举原图的每一条边。对于边两边的点:

    (1)属于同一个块,答案如上面说的

    (2)属于不同块。则设他们所在的块为u, v。可以知道在刚才那棵树中,u一定是v的父亲或者v一定是u的父亲(树上的边直接连接了他们),为了表达方便我们设u是父亲。删去边后变成了v子树以及除了v子树以外的一块。因为有maxn[v] <= maxn[u],且有maxn[v] + 1不在v子树上,所以maxn[v] +1一定在另一块上,也就是他们分开了,那么这是一组可行解。怎么证明是最大呢= =因为maxn[v]是v子树上最大值,没有别的值比他大了。。且不会选择出maxn[v] = n因为v一定是儿子,而n在整棵树的根上,他所在的块一定不是儿子。

 

 

大概说的挺清楚了吧,,啰嗦患者的日常= =

其他看代码吧,虽然注释也没多少= = 然后minn是没用的数组哈哈哈= =

  1 #include <cstring>
  2 #include <cstdio>
  3 #include <algorithm>
  4 using namespace std;
  5 const int N = 100005;
  6 
  7 int head[N], maxn[N], minn[N], dfn[N], low[N], st[N], belong[N];
  8 int deep[N];
  9 
 10 struct point{
 11     int u, v, next;
 12     point(){};
 13     point(int x, int y, int z){
 14         u=x, v = y, next = z;
 15     }
 16 }p[N<<1];
 17 int no, top, num, id;
 18 struct Ans{
 19     int x, y;
 20     Ans(){};
 21     Ans(int _u, int _v){
 22         x = _u; y = _v;
 23     }
 24 }ans[N];
 25 void init(){
 26     memset(head, -1, sizeof(head));
 27     memset(dfn, -1, sizeof(dfn));
 28     memset(maxn, 0, sizeof(maxn));
 29     memset(minn, 0x3f, sizeof(minn));
 30     no = id = num = top = 0;
 31 }
 32 
 33 void add(int x, int y){
 34     p[no] = point(x, y, head[x]);
 35     head[x] = no++;
 36     p[no] = point(y, x, head[y]);   head[y] =no++;
 37 }
 38 //tarjan求强连通,belong[i]表示属于哪个块
 39 //记录每个块中编号最大值
 40 void tarjan( int x, int fa){
 41     int cnt = 0;
 42     low[x] = dfn[x] = ++num;
 43     st[++top] = x;
 44     int i, y;
 45     for(i = head[x]; i != -1; i = p[i].next){
 46         y = p[i].v;
 47         if(y == fa)continue;
 48         if(dfn[y] == -1)    {
 49             tarjan(y, x);
 50             low[x] = min(low[x], low[y]);
 51         }
 52         else low[x] = min(low[x], dfn[y]);
 53     }
 54     if(dfn[x] == low[x]){
 55         id ++;
 56         do{
 57             y = st[top--];
 58             belong[y] = id;
 59             maxn[id] = max(maxn[id], y);
 60             minn[id] = min(minn[id], y);
 61         }while(x != y);
 62     }
 63 }
 64 //maxn表示i 及其子树的最大值
 65 void dfs(int x, int fa){
 66     int i, y;
 67     for(i = head[x]; i != -1; i = p[i].next){
 68         y = p[i].v;
 69         if(y == fa) continue;
 70         deep[y] = deep[x] + 1;
 71         dfs(y, x);
 72         maxn[x] = max(maxn[x], maxn[y]);
 73     }
 74 
 75 }
 76 int main(){
 77     int TC, n, m, i, x, y, u, v;
 78     scanf("%d", &TC);
 79     while(TC--){
 80         scanf("%d%d", &n, &m);
 81         init();
 82         for(i = 1; i <= m; i++){
 83             scanf("%d%d", &x, &y);
 84             add(x, y);
 85         }
 86         tarjan(1, 1);
 87 
 88         m = no;
 89         no = 0;
 90         memset(head, -1, sizeof(head));
 91         //重新建出树
 92         for(i = 0; i < m; i+= 2){
 93             x = belong[p[i].u]; y = belong[p[i].v];
 94             //属于同一个块,非桥边,删了之后不出现不通的点
 95             if(x == y) ans[i/2] = Ans(0, 0);
 96             else {
 97                 ans[i/2] = Ans(x, y);
 98                 add(x, y);
 99             }
100         }
101         deep[1] = 0;
102         //以n所在的块为根,dfs这棵树,求出子树的maxn
103         dfs(belong[n], 0);
104         m >>= 1;
105         for(i = 0; i < m; i++){
106             if(ans[i].x == 0)   printf("0 0\n");
107             else{
108                 //因为只隔一条边
109                 u = ans[i].x;   v  = ans[i].y;
110                 if(deep[u] > deep[v]){
111                     printf("%d %d\n", maxn[u], maxn[u] + 1);
112                 }   else {
113                     printf("%d %d\n", maxn[v], maxn[v] + 1);
114                 }
115             }
116         }
117     }
118     return 0;
119 }

 

posted @ 2015-08-21 00:24  bbbbq  阅读(195)  评论(0编辑  收藏  举报