BZOJ5218: [Lydsy2017省队十连测]友好城市(kosaraju算法)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35649707/article/details/82841070

传送门

题解:
利用kosaraju+bitset可以在知道邻接矩阵的情况下 O ( n 2 32 ) O(\frac{n^2}{32}) 解决强连通分量计数。

用回滚莫队即可在 O ( m m ) O(m \sqrt{m}) 的时间内获得所有询问的邻接矩阵了。 时间复杂度 O ( m m + q n 2 32 ) O( m\sqrt{m} + q\frac{n^2}{32})

#include <bits/stdc++.h>
#include <bitset>
using namespace std;
typedef pair <int,int> pii;

const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}
inline void W(int x) {
	static int buf[50];
	if(!x) {putchar('0'); return;}
	if(x<0) {putchar('-'); x=-x;}
	while(x) {buf[++buf[0]]=x%10; x/=10;}
	while(buf[0]) {putchar(buf[buf[0]--]+'0');}
}

const int N=151, M=3e5+50, S=450;
typedef bitset <N> bs;
struct data {
	int l,r,id;
	data(int l,int r,int id) : l(l),r(r),id(id) {}
	friend inline bool operator <(const data &a,const data &b) {return a.r<b.r;}
};
int n,m,q,a[M],b[M],bg[M],ed[M],ans[M],h;
bs ori[N],rev[N],t1[N],t2[N],vis;
vector <data> qry[M/S+2][M/S+2];
int out[N],ind,res;

inline void dfs(int x) {
	bs now; vis[x]=1;
	while((now=ori[x]^(ori[x]&vis)), now.any()) {
		int v=now._Find_first();
		dfs(v);
	} out[++ind]=x;
}
inline int dfs_rev(int x) {
	int s=1; bs now; vis[x]=1;
	while((now=rev[x]^(rev[x]&vis)), now.any()) {
		int v=now._Find_first();
		s+=dfs_rev(v);
	} return s;
}
inline int kosaraju() {
	vis.reset(); ind=0;
	for(int i=1;i<=n;i++) 
		if(!vis[i]) dfs(i);
	vis.reset(); res=0;
	for(int i=n;i>=1;i--) 
		if(!vis[out[i]]) {
			int x=dfs_rev(out[i]);
			res+=x*(x-1)/2;
		}
	return res;
}

inline void clear() {for(int i=1;i<=n;i++) ori[i].reset(), rev[i].reset();}
inline void inc(int l,int r) {
	ori[l].set(r); 
	rev[r].set(l);
}
inline void bf_solve(int l,int r,int id) {
	for(int i=l;i<=r;i++) inc(a[i],b[i]);
	ans[id]=kosaraju(); clear();
}
int main() {
	n=rd(), m=rd(), q=rd();
	for(int i=1;i<=m;i++) a[i]=rd(), b[i]=rd();
	for(int l=1,r;l<=m;l=r+1) {
		r=min(l+S-1,m);
		bg[++h]=l; ed[h]=r;
	}
	for(int i=1;i<=q;i++) {
		int l=rd(), r=rd();
		if(r-l+1<=2*S) bf_solve(l,r,i);
		else qry[(l-1)/S+2][r/S].push_back(data(l,r,i));
	}
	for(int i=1;i<=h;i++) for(int j=i;j<=h;j++) 
		sort(qry[i][j].begin(),qry[i][j].end());
	for(int i=1;i<=h;i++) {
		int r=ed[i-1];
		for(int j=i;j<=h;j++) {
			while(r<ed[j]) ++r, inc(a[r],b[r]);
			for(int z=0;z<qry[i][j].size();++z) {
				data &q=qry[i][j][z];
				while(r<q.r) ++r, inc(a[r],b[r]);
				
				for(int i=1;i<=n;i++) t1[i]=ori[i], t2[i]=rev[i];
				for(int t=bg[i]-1;t>=q.l;--t) inc(a[t],b[t]);
				ans[q.id]=kosaraju();
				for(int i=1;i<=n;i++) ori[i]=t1[i], rev[i]=t2[i];
			}
		} clear();
	}
	for(int i=1;i<=q;i++) W(ans[i]), putchar('\n');
}

猜你喜欢

转载自blog.csdn.net/qq_35649707/article/details/82841070
今日推荐