[UPC | 山东省赛] The Largest SCC | Tarjan强连通分量瞎搞 + 状态还原

题目描述

Consider a directed graph with N (1 <= N <= 1000) vertices and M (0 <=M <= 20000) edges. The edges are numbered from 1 to M and the vertices are numbered from 1 to N. Now I will make ONE edge bidirectional, and you are to tell me the number of vertices of the largest strong connected components in the new graph.The largest strong connected components is the strong connected components which has the most vertices. After the operation, I will change the edge back. There will be up to Q (1 <= Q <= 20000) such queries.

输入

At the firest of the input comes an integer t, indicates the testcases to follow.
The first line of each case contains three numbers N, M and Q. Then there will be M lines, each of them contains two numbers a,b (a! = b; 1 <= a; b <= N) means there is a directed edge between a and b. The last of each case contains Q lines, each of them contains one integer q, means the edge numbered q will be change to bidirectional. There will not be duplicated edges.

输出

For every query, output one line contains only one integer number, which is the number of vertices of the biggest strong connected components.

样例输入

1
5 4 2
1 2
2 3
1 3
4 1
1
3

样例输出

2
3

题意:
给出 n n n个点 m m m条边的图,边为有向边, q q q此查询,如果每次将第 k k k条边变为双向边,问改变这一条边为双向边之后,图中的最大的强连通分量里面包含多少个点

思路1(wa):
首先求出SCC,将在同一个强连通分量里面的点用并查集维护在一起(此时顺便找出一个最大值),然后再加边[变为双向边其实就是加了一条从原来的终点向之前的起点的一条边]的时候,查看边的两个端点是不是在同一个强连通分量中,如果在同一个强连通分量中,就直接输出原来的最大值,如果说不是在同一个强连通分量中,就将两个强连通分量的大小与之前的最大值求一个最大进行输出,
这样是不对的,因为改变一条边之后,可能影响的不是两个端点所在的连通块,所以说这里不能够用这种方法来处理
应该是:
思路2(ac):
因为点的个数只有 1000 1000 1000,所以我们直接每次加入一条新的边之后,重新进行Tarjan
比如说:第k条边是u->v 的,那么说我们应该加入一从v->u的边,这样一来,然后我们从u点开始重新进行Tarjan,因为在原始的图中,是u->v的,这样一来我们只需要记录影响的大小和原先最大值的大小取一个最大值即可
在进行Tarjan的时候,如果是一开始的预处理,是可以加入新的强连通分量的,但是在处理q此询问的时候,不可以有新的强连通分量产生,因为不能对原图进行修改,(每次询问都是单独的),而对于新加入的边,也要在下一次操作之前去掉,但是强连通分量的大小是可以改变的,每次找到最大的size

Code:

int n, m, q;
struct node {
	int to, nex;
} e[maxn << 2];
int cnt, head[maxn], dfc;
int dfn[maxn], low[maxn], pos[maxn];
int num[maxn], vis[maxn];
int cntSCC, ans;
void init() {
	cnt = dfc = cntSCC = 0;
	for(int i = 1; i <= n; i++) {
		head[i] = -1;
		pos[i] = vis[i] = 0;
	}
}
void add(int u, int v) {
	e[cnt].to = v;
	e[cnt].nex = head[u];
	head[u] = cnt ++;
}
stack<int> stk;
int mx,premx;
void Tarjan(int x) {
	int u = x;
	dfn[u] = low[u] = ++ dfc;
	vis[u] = 1;
	stk.push(u);
	for(int i=head[u]; ~i; i=e[i].nex) {
		int v = e[i].to;
		if(!dfn[v]) {
			Tarjan(v);
			low[u] = min(low[u],low[v]);
		} else if(vis[v]) {
			low[u] = min(low[u],dfn[v]);
		}
	}
	int tp;
	if(low[u] == dfn[u]) {
		++ cntSCC;
		do{
			tp = stk.top();
			stk.pop();
			vis[tp] = 0;
			if(vis[0]) pos[tp] = cntSCC;
			num[cntSCC] ++;
			mx = max(mx,num[cntSCC]);
		}while(tp != u);
	}
}
typedef pair<int,int> PII;
vector<PII> save;
void ClearStack(){
	while(stk.size()) stk.pop();
}
int main() {
	int _ = read;
	while(_ --) {
		n = read,m = read,q = read;
		init();
		save.clear();
		memset(dfn,0,sizeof dfn);
		memset(low,0,sizeof low);
		memset(vis,0,sizeof vis);
		memset(num,0,sizeof num);
		vis[0] = 1;
		for(int i = 1; i <= m; i++) {
			int u = read, v = read;
			add(u, v);
			save.push_back({u,v});
		}
		ClearStack();
		mx = 0,premx = 0;
		for(int i=1; i<=n; i++) {
			if(!dfn[i]) Tarjan(i);
		}
		premx = mx;
		
//		cout << mx << endl;
//		cout << premx << endl;
		vis[0] = 0;
		while(q --) {
			int id = read - 1;
			PII eg = save[id];
			int u = eg.first,v = eg.second;
//			cout << u <<"  ->  " << v<< endl;
			if(pos[u] == pos[v]) {
				printf("%d
",mx);
				continue;
			}
			add(v,u);
			memset(dfn,0,sizeof dfn);
//			memset(low,0,sizeof low);
			dfc = 0;
			ClearStack();
			Tarjan(u);
			printf("%d
",mx);
			mx = premx;
			head[v] = e[--cnt].nex;
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/PushyTao/p/15459772.html