HDU 5409 CRB and Graph(桥边+乱搞)



题意:一个联通的无向图, 对于每一条边, 若删除该边后存在两点不可达,则输出这两个点, 如果存在多个则输出第一个点尽可能大,第二个点尽可能小的。 不存在输出0 0。

思路:很明显是求桥,写完了以后发现有更优美的写法貌似不用缩点,直接在Tarjan求桥边的过程中就可以计算出答案。

虽然写的恶心,但思路还是比较好懂,因为一条桥边将图分成两个连通分量,记录两个联通分量中最大的点max1 max2, 如果max1!=n 则答案就是max1 max1+1否则max2 max2+1,所以答案找出桥边缩点,然后以结点n为根进行一次dp,求出以每个点为根的子树中的最大值,并求出每个节点的深度,那么对于两个节点,答案就是深度大的那颗子树中的最大值和最大值加一。


#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

const int MAXN = 100100;//点数
const int MAXM = 200200;//边数,因为是无向图,所以这个值要*2
int n, m, T;
struct Edge
{
    int from, to, next;
    bool cut;//是否是桥标记
}edge[MAXM];
int head[MAXN], tot;
int Low[MAXN],DFN[MAXN],SLT[MAXN];
int Index;
bool vis2[MAXN];
int bridge;//桥的数目
vector<int> G[MAXN]; //所点后形成的图
int maxv[MAXN];  //每颗子树里的最大值
void addedge(int u,int v)
{
    edge[tot].from = u;edge[tot].to = v;edge[tot].next = head[u];edge[tot].cut=false;
    head[u] = tot++;
}

int Tarjan(int u, int fa) { //u在dfs树中的父节点为fa
	int lowu = DFN[u] = ++Index;
	for(int i = head[u]; i != -1; i = edge[i].next) {
		int v = edge[i].to;
		if(!DFN[v]) {   //没有访问过v
			int lowv = Tarjan(v, u);
			lowu = min(lowu, lowv);    //用后代的low函数更新u的low函数
			if(lowv > DFN[u]) {
				edge[i].cut = 1;
				edge[i^1].cut = 1;
			}
		}
		else if(DFN[v] < DFN[u] && v != fa)  lowu = min(lowu, DFN[v]);  //用反向边更新u的low函数
	}
	Low[u] = lowu;
	return lowu;
}
void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
    for(int i = 1; i <= n; i++) G[i].clear();
    memset(maxv, -1, sizeof(maxv));
    memset(vis2, 0, sizeof(vis2));
    memset(DFN,0,sizeof(DFN));
}
int dep[MAXN];
void found_SLT(int cur, int id) {
	SLT[cur] = id;
	vis2[cur] = 1;
	for(int i = head[cur]; i != -1; i = edge[i].next) {
		int u = edge[i].to;
		if(edge[i].cut || vis2[u]) continue;
		found_SLT(u, id);
	}
}
void dfs(int cur, int fa) {
	for(int i = 0; i < G[cur].size(); i++) {
		int u = G[cur][i];
		if(u == fa) continue;
		dep[u] = dep[cur] + 1;
		dfs(u, cur);
		maxv[cur] = max(maxv[cur], maxv[u]);
	}
}
void solve()
{
    bridge = Index = 0;
    //
//	if(m!=n-1) {
	Tarjan(1,-1);
	//cout << bridge << endl;
	int id = 0;
    for(int i = 1; i <= n; i++) {
		if(!vis2[i]) found_SLT(i, ++id);
    }
    //cout << id << endl;

    //for(int i = 1; i <= n; i++) SLT[i] = i;

	for(int i = 1;i <= n;i++)
       for(int j = head[i];j != -1;j = edge[j].next) {
			int u = edge[j].to;
			maxv[SLT[u]] = max(maxv[SLT[u]], u);
			if(SLT[i]==SLT[u]) continue;
			G[SLT[i]].push_back(SLT[u]);

       }

    //cout << G[1].size() << endl;
    int root = SLT[n];
    //cout << SLT[n] << endl;
    dep[root] = 0;
	//for(int i = 1; i <= n; i++) cout << maxv[i] << endl;
	dfs(root, -1);
	//for(int i = 1; i <= n; i++) cout << G[i].size() << endl;
	//for(int i = 1; i <= n; i++) cout << dep[i] << endl;
	//cout << " FUck " << endl;

}
int main() {
    //freopen("1004.in", "r", stdin);
	//freopen("input.txt", "r", stdin);
	scanf("%d", &T);
	while(T--) {
		scanf("%d%d", &n, &m);
		//if(T==1) cout << n << endl << m << endl;
		init();
		for(int i = 0; i < m; i++) {
			int u, v; scanf("%d%d", &u, &v);
			addedge(u, v);
			addedge(v, u);
		}

		solve();
		//if(T==1) cout << "gan " << endl;
		for(int i = 0; i < 2*m; i+=2) {
			int u = edge[i].from, v = edge[i].to;
			if(SLT[u]==SLT[v]) puts("0 0");
			else {
				if(dep[SLT[u]]>dep[SLT[v]]) printf("%d %d\n", maxv[SLT[u]], maxv[SLT[u]]+1);
				else printf("%d %d\n", maxv[SLT[v]], maxv[SLT[v]]+1);
			}
		}
		//cout << T << endl;
	}
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值