用双指针扫描来找环,加入 (r) 位置的边后,若形成了环,就删去 (l) 位置的边,直到环断掉,加边删边和判定连通性用 (LCT) 维护即可。
考虑如何计算环的贡献,对于区间 ([l,r]),若其形成了环,则区间 ([l,r+1],[l,r+2] dots [l,m]) 都形成了环。得最终的贡献为区间 ([l,r]) 都加上 (m-r+1),区间 ([r+1,m]) 加上一个首项为 (m-r),公差为 (-1) 的等差数列。用线段树维护差分数列即可。
#include<bits/stdc++.h>
#define maxn 200010
#define maxm 800010
#define ls (cur<<1)
#define rs (cur<<1|1)
#define mid ((l+r)>>1)
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int m,root=1,pos=1;
int fa[maxn],ch[maxn][2],rev[maxn];
ll sum[maxm],add[maxm],ans[maxn];
struct edge
{
int x,y;
}e[maxn];
void pushadd(int cur,int l,int r,ll v)
{
sum[cur]+=v*(r-l+1),add[cur]+=v;
}
void pushdown(int cur,int l,int r)
{
if(!add[cur]) return;
pushadd(ls,l,mid,add[cur]),pushadd(rs,mid+1,r,add[cur]),add[cur]=0;
}
void modify(int L,int R,int l,int r,ll v,int cur)
{
if(L>R) return;
if(L<=l&&R>=r)
{
pushadd(cur,l,r,v);
return;
}
pushdown(cur,l,r);
if(L<=mid) modify(L,R,l,mid,v,ls);
if(R>mid) modify(L,R,mid+1,r,v,rs);
sum[cur]=sum[ls]+sum[rs];
}
void dfs(int l,int r,int cur)
{
if(l==r)
{
ans[l]=sum[cur];
return;
}
pushdown(cur,l,r);
dfs(l,mid,ls),dfs(mid+1,r,rs);
}
bool check(int x)
{
return ch[fa[x]][1]==x;
}
bool notroot(int x)
{
return ch[fa[x]][0]==x||ch[fa[x]][1]==x;
}
void pushrev(int x)
{
rev[x]^=1,swap(ch[x][0],ch[x][1]);
}
void spread(int x)
{
if(!rev[x]) return;
pushrev(ch[x][0]),pushrev(ch[x][1]),rev[x]=0;
}
void rotate(int x)
{
int y=fa[x],z=fa[y],k=check(x),w=ch[x][k^1];
if(notroot(y)) ch[z][check(y)]=x;
ch[x][k^1]=y,ch[y][k]=w;
if(w) fa[w]=y;
fa[x]=z,fa[y]=x;
}
void all(int x)
{
if(notroot(x)) all(fa[x]);
spread(x);
}
void splay(int x)
{
all(x);
for(int y;notroot(x);rotate(x))
if(notroot(y=fa[x]))
rotate(check(x)^check(y)?x:y);
}
void access(int x)
{
for(int y=0;x;y=x,x=fa[x]) splay(x),ch[x][1]=y;
}
void makeroot(int x)
{
access(x),splay(x),pushrev(x);
}
void split(int x,int y)
{
makeroot(x),access(y),splay(y);
}
int findroot(int x)
{
access(x),splay(x);
while(ch[x][0]) x=ch[x][0];
splay(x);
return x;
}
void link(int x,int y)
{
split(x,y),fa[x]=y;
}
void cut(int x,int y)
{
split(x,y),fa[x]=ch[y][0]=0;
}
int main()
{
read(m);
for(int i=1;i<=m;++i) read(e[i].x),read(e[i].y);
for(int i=1;i<=m;++i)
{
int x=e[i].x,y=e[i].y;
while(findroot(x)==findroot(y))
{
modify(pos,pos,1,m,m-i+1,root);
modify(i+1,m,1,m,-1,root);
cut(e[pos].x,e[pos].y),pos++;
}
link(x,y);
}
dfs(1,m,root);
for(int i=1;i<=m;++i)
ans[i]+=ans[i-1],printf("%lld ",ans[i]);
return 0;
}