HDU6072 Logical Chain

版权声明:大佬您能赏脸,蒟蒻倍感荣幸,还请联系我让我好好膜拜。 https://blog.csdn.net/ShadyPi/article/details/82902798

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=6072

Logical Chain

Problem Description

Every time you come across a problem you’ve never seen before, haven’t you thought of something that is familiar to you? If so, you might think of something else, then more and more things will come to your mind. This is what is called ‘‘Logical Chain’’. Lu Xun’s work also described such interesting phenomenon.

Assume there are n things, labeled by 1,2,…,n. Little Q’s mind can be expressed by a n×n matrix g. If he can think of j when he comes across i, then gi,j is 1, otherwise it’s 0. For two different things u and v, if u can lead to v directly or indirectly and v can also lead to u directly or indirectly, then the pair (u,v) is called a ‘‘Looping Pair’’.

Little Q’s mind changes all the time. On i-th day, there are ki positions (u,v) in matrix g flipped(0 to 1 and 1 to 0). Please write a program to figure out the number of ‘‘Looping Pairs’’ after each day’s all changes.

Note : (u,v) and (v,u) should not be counted twice.

Input

The first line of the input contains an integer T(1≤T≤15), denoting the number of test cases.

In each test case, there are 2 integers n,m(1≤n≤250,1≤m≤25000) in the first line, denoting the number of things and days.\par
For the next n lines, each line contains n integers gi,1,gi,2,…,gi,n(0≤gi,j≤1,gi,i=0), denoting the matrix g.

For the next m parts, there is an integer ki(1≤ki≤10) in the first line, denoting the number of changes happened on that day.

For the next ki lines, each line contains 2 integers u,v(1≤u,v≤n,u≠v), denoting a changed position in g.

It is guaranteed that each position will be changed at most once per day.

Output

For each day, print a single line containing an integer, denoting the number of ‘‘Looping Pairs’’ after that day’s all changes.

Sample Input

1
4 2
0010
1000
0000
0000
3
1 4
3 2
1 2
2
4 3
2 3

Sample Output

3
6

题解

题面真是有毒,大家可以自己去搜无码的原文。。。

题意大概是说求动态有向图上能互相到达的点对数。

那么我们就要维护 s c c scc 及每个 s c c scc 的大小,考虑到 T a r j a n \mathcal{Tarjan} 复杂度为 O ( n + m ) O(n+m) 而且修改边的操作非常爆炸,无法处理多组询问,所以我们使用 K o s a r a j u \mathcal{Kosaraju} 算法, K o s a r a j u \mathcal{Kosaraju} 不需要遍历到所有的边,只需要遍历所有的点,又因为 n 150 n\le 150 ,我们可以用邻接矩阵存图方便修改,复杂度 O ( n 2 ) O(n^2)

貌似 K o s a r a j u \mathcal{Kosaraju} 也没优化什么?我们还可以添加一些优化,显然我们可以将边表压进 B i t s e t \mathcal{Bitset} 里,每次将边表 & v i s \&vis v i s vis 1 1 表示没有到达, 0 0 表示已经到过),再用 _ _ b u i l t i n _ c t z ( ) \_\_builtin\_ctz() 就可以求出当前 B i t s e t \mathcal{Bitset} 里没有到过的点,这样复杂度就变成了 O ( n 2 32 ) O(\frac{n^2}{32}) ,乖乖 A C \mathcal{AC}

代码
#include<bits/stdc++.h>
#define uint unsigned int
#define lg(x) __builtin_ctz(x)
using namespace std;
const int M=320,bit=32;
const uint inf=0xffffffff;
uint mmp[M][M/bit],mmp2[M][M/bit],vis[M/bit];
int cot[M],sta[M],top,T,n,m,ans,tot;
char ch[M];
void dfs1(int v){vis[v/bit]&=inf^(1<<v%bit);for(int i=0;i<=n/bit;++i)for(;mmp2[v][i]&vis[i];)dfs1(lg(mmp2[v][i]&vis[i])+i*bit);sta[++top]=v;}
void dfs2(int v){vis[v/bit]&=inf^(1<<v%bit),++cot[tot];for(int i=0;i<=n/bit;++i)for(;mmp[v][i]&vis[i];dfs2(lg(mmp[v][i]&vis[i])+i*bit));}
void work()
{
	int i;ans=tot=top=0;memset(cot,0,sizeof(cot));
	for(memset(vis,255,sizeof(vis)),i=1;i<=n;++i)if(vis[i/bit]>>i%bit&1)dfs1(i);
	for(memset(vis,255,sizeof(vis)),i=top;i>=1;--i)if(vis[sta[i]/bit]>>sta[i]%bit&1)++tot,dfs2(sta[i]);
	for(int i=1;i<=tot;++i)ans+=cot[i]*(cot[i]-1)/2;
	printf("%d\n",ans);
}
void reset(){memset(mmp,0,sizeof(mmp)),memset(mmp2,0,sizeof(mmp2));}
void in()
{
	scanf("%d%d",&n,&m);
	for(int i=1,j;i<=n;++i)for(scanf("%s",ch+1),j=1;j<=n;++j)if(ch[j]=='1')mmp[i][j/bit]|=1<<j%bit,mmp2[j][i/bit]|=1<<i%bit;
}
void ac(){for(int k,a,b;m--;work())for(scanf("%d",&k);k--;)scanf("%d%d",&a,&b),mmp[a][b/bit]^=1<<b%bit,mmp2[b][a/bit]^=1<<a%bit;}
int main(){for(scanf("%d",&T);T--;)reset(),in(),ac();}

猜你喜欢

转载自blog.csdn.net/ShadyPi/article/details/82902798