一道十分巧妙的分治题,很明显是需要离线的
那么我们看看时间轴分了类后,一条边有贡献当且仅当连接的两个点在左边没有形成环
如果前半部分在左边能够形成环,我们就把他们加入下一层的左边,否则就加入右边
然后递归tarjan处理,已经成环的就可以直接并查集合并为一个点,那么可以发现复杂度就是mlogm
理解了之后就是非常简单的一道题了
#include<bits/stdc++.h>
using namespace std;
int u[1000005],v[1000005],n,m;
long long ans[1000005],tot;
int size[100005],father[100005],instk[100005];
vector <int> id,vec[100005];
int dfn[100005],low[100005],color[100005],vis[100005],cnt,stk[100005],top;
int minn(int x,int y){if(x<y) return x;return y;}
inline int find(int x)
{
if(x==father[x]) return x;
return father[x]=find(father[x]);
}
inline void unionn(int x,int y)
{
int r1=find(x),r2=find(y);
if(r1==r2)return;
father[r1]=r2;
size[r2]+=size[r1];
}
inline void tarjan(int x)
{
low[x]=dfn[x]=++cnt;
stk[++top]=x;instk[x]=1;
for(vector <int> :: iterator it=vec[x].begin(),ed=vec[x].end();it!=ed;it++)
{
int y=*it;
if(!dfn[y])
{
tarjan(y),low[x]=minn(low[x],low[y]);
}
else if(instk[y]) low[x]=minn(low[x],dfn[y]);
}
if(dfn[x]==low[x])
{
int sum=0;
while(233)
{
int now=stk[top--];
instk[now]=0;
tot+=1ll*sum*size[now];
sum+=size[now];
color[now]=x;
if(now==x) break;
}
}
}
inline void clear(vector <int> a)
{
for(int i=0;i<a.size();i++)
{
int x=a[i];
dfn[x]=low[x]=vis[x]=0;
vec[x].clear();
}
}
inline void solve(int l,int r,vector <int> id)
{
int mid=(l+r)>>1;
vector <int> cur;
for(int i=0;i<id.size();i++)
if(id[i]<=mid)
{
int x=find(u[id[i]]),y=find(v[id[i]]);
if(!vis[x]) vis[x]=1,cur.push_back(x);
if(!vis[y]) vis[y]=1,cur.push_back(y);
vec[x].push_back(y);
}
tot=cnt=top=0;
for(int i=0;i<cur.size();i++)
if(!dfn[cur[i]]) tarjan(cur[i]);
if(l==r)
{
ans[l]=ans[l-1]+tot;
for(int i=0;i<cur.size();i++) unionn(cur[i],color[cur[i]]);
clear(cur);
return;
}
vector <int> lef,rig;
for(int i=0;i<id.size();i++)
{
int now=id[i],x=find(u[now]),y=find(v[now]);
if(vis[x]&&vis[y]&&color[x]==color[y])
{
if(now<=mid) lef.push_back(now);
}
else rig.push_back(now);
}
clear(cur);
solve(l,mid,lef);solve(mid+1,r,rig);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d",&u[i],&v[i]),id.push_back(i);
for(int i=1;i<=n;i++)
size[i]=1,father[i]=i;
solve(1,m,id);
for(int i=1;i<=m;i++)
printf("%lld\n",ans[i]);
return 0;
}