bzoj 5218: [Lydsy2017省队十连测]友好城市

题意:

bzoj 5218: [Lydsy2017省队十连测]友好城市bzoj 5218: [Lydsy2017省队十连测]友好城市
这题显然直接tarjan是做不了的。

这里安利另一个求SCC的算法Kosaraju,学习的话可以见这篇博客

于是结合莫队,我们有了个暴力。

发现主要瓶颈是dfs过程中找最小的未经过的点,我们用bitset优化一下就过了。

注意有重边,不能直接在biset中删除,要开个邻接矩阵判一下。

code:

#include<bits/stdc++.h>
using namespace std;
#define re register
typedef long long ll;
const int maxn=200;
const int maxm=3*1e5+10;
const int maxq=50010;
int n,m,Q,t,block,nowl=1,nowr,tot,cnt;
int pos[maxm],size[maxn],a[maxn];
int cnt1[maxn][maxn],cnt2[maxn][maxn];
ll ans[maxq];
struct Edge{int u,v;}E[maxm];
struct Query{int l,r,id;}qr[maxq];
bitset<maxn>vis;
bitset<maxn>e1[maxn],e2[maxn];
inline int read()
{
	re char c=getchar();re int res=0,f=1;
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
	return res*f;
}
char num[35];
inline void write(ll x) 
{
    if(!x){putchar('0');return;}
	re ll tmp=x>0?x:-x;
    if(x<0)putchar('-');
    re int cnt=0;
    while(tmp>0) 
	{
        num[cnt++]=tmp%10+'0';
        tmp/=10;
    }
    while(cnt>0)putchar(num[--cnt]);
}
inline bool cmp(Query x,Query y)
{
	if(pos[x.l]==pos[y.l])
	{
		if(pos[x.l]&1)return x.r<y.r;
		else return x.r>y.r;
	}
	else return x.l<y.l;
}
inline void add(int id)
{
	re int x=E[id].u,y=E[id].v;
	cnt1[x][y]++,cnt2[y][x]++;
	if(cnt1[x][y]==1)e1[x].set(y);
	if(cnt2[y][x]==1)e2[y].set(x);
}
inline void del(int id)
{
	re int x=E[id].u,y=E[id].v;
	cnt1[x][y]--,cnt2[y][x]--;
	if(!cnt1[x][y])e1[x].reset(y);
	if(!cnt2[y][x])e2[y].reset(x);
}
void dfs1(int x)
{
	vis.reset(x);
	bitset<maxn>now=vis&e1[x];
	while(now.any())
	{
		dfs1(now._Find_first());
		now&=vis;
	}
	a[++cnt]=x;
}
void dfs2(int x)
{ 
	size[tot]++;vis.reset(x);
	bitset<maxn>now=vis&e2[x];
	while(now.any())
	{
		dfs2(now._Find_first());
		now&=vis;
	}
}
inline ll solve()
{
	memset(size,0,sizeof(size));
	vis.set();cnt=tot=0;
	re ll res=0;
	for(re int i=1;i<=n;i++)if(vis.test(i))dfs1(i);
	vis.set();
	for(re int i=cnt;i;i--)if(vis.test(a[i]))tot++,dfs2(a[i]);
	for(re int i=1;i<=tot;i++)res+=size[i]*(size[i]-1)/2;
	return res;
}
int main()
{
	//freopen("test.in","r",stdin);
	//freopen("test.out","w",stdout);
	n=read(),m=read(),Q=read();
	for(re int i=1;i<=m;i++)E[i].u=read(),E[i].v=read();
	for(re int i=1;i<=Q;i++)qr[i].l=read(),qr[i].r=read(),qr[i].id=i;
	t=pow(m,1.0*3/5);
	for(re int i=1;i<=m;i++)pos[i]=(i-1)/t+1;
	sort(qr+1,qr+Q+1,cmp);
	for(re int i=1;i<=Q;i++)
	{
		while(nowl<qr[i].l)del(nowl++);
		while(nowl>qr[i].l)add(--nowl);
		while(nowr<qr[i].r)add(++nowr);
		while(nowr>qr[i].r)del(nowr--);
		ans[qr[i].id]=solve();
	}
	for(re int i=1;i<=Q;i++,puts(""))write(ans[i]);
	return 0;
}