卧薪尝胆,厚积薄发。
连环病原体
Date: Fri Nov 23 07:34:22 CST 2018 In Category: NoCategory

Description:

一张 $n$ 点 $m$ 边无向图,每条边有编号,若一个区间内的边能连成环,则称这个区间为好区间,求每条边分别在多少个好区间内。
$1\leqslant n\leqslant 200000$

Solution:

枚举区间右端点 $r$ ,用 $LCT$ 维护当前生成树,如果 $e[r]$ 两个点已经连起来了就不停移动左端点直到没有连起来,这样就找到了一个以 $r$ 为右端点的极长无环区间,然后二次差分一下就行了。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<stack>
#include<cctype>
#include<cstring>
using namespace std;
inline int rd()
{
register int res = 0,f = 1;
register char c = getchar();
while(!isdigit(c))
{
if(c == '-')f = -1;
c = getchar();
}
while(isdigit(c))
{
res = (res << 1) + (res << 3) + c - '0';
c = getchar();
}
return res * f;
}
#define MAXN 400010
#define MAXM 200010
int m;
struct edges
{
int u,v;
}es[MAXM];
struct node
{
int c[2],fa;
bool rev;
}t[MAXN];
inline bool isroot(int k){return (t[t[k].fa].c[0] != k && t[t[k].fa].c[1] != k);}
inline int id(int k){return (t[t[k].fa].c[0] == k ? 0 : 1);}
inline void connect(int k,int f,int p){t[k].fa = f;t[f].c[p] = k;return;}
inline void rotate(int x)
{
register int y = t[x].fa,z = t[y].fa,fx = id(x),fy = id(y);
if(!isroot(y))t[z].c[fy] = x;
t[x].fa = z;
connect(t[x].c[fx ^ 1],y,fx);
connect(y,x,fx ^ 1);
return;
}
stack<int> s;
inline void pushdown(int k)
{
if(t[k].rev)
{
t[t[k].c[0]].rev ^= 1;t[t[k].c[1]].rev ^= 1;
swap(t[k].c[0],t[k].c[1]);t[k].rev = false;
}
return;
}
inline void splay(int x)
{
s.push(x);
for(register int i = x;!isroot(i);i = t[i].fa)s.push(t[i].fa);
while(!s.empty()){pushdown(s.top());s.pop();}
while(!isroot(x))
{
register int y = t[x].fa;
if(isroot(y)){rotate(x);break;}
if(id(x) == id(y)){rotate(y);rotate(x);}
else{rotate(x);rotate(x);}
}
return;
}
inline void access(int k){for(register int i = 0;k;i = k,k = t[k].fa){splay(k);t[k].c[1] = i;}return;}
inline void makeroot(int k){access(k);splay(k);t[k].rev ^= 1;return;}
inline void link(int x,int y){makeroot(x);t[x].fa = y;return;}
inline void cut(int x,int y){makeroot(x);access(y);splay(y);t[x].fa = t[y].c[0] = 0;return;}
inline int findroot(int k){access(k);splay(k);while(t[k].c[0] != 0)k = t[k].c[0];splay(k);return k;}
long long diff[MAXN],ans[MAXN];
int main()
{
scanf("%d",&m);
for(register int i = 1;i <= m;++i)
{
es[i].u = rd();es[i].v = rd();
}
for(register int l = 1,r = 1;r <= m;++r)
{
while(findroot(es[r].u) == findroot(es[r].v))
{
cut(es[l].u,es[l].v);
++l;
}
link(es[r].u,es[r].v);
++diff[l];--diff[r + 1];
ans[r + 1] -= (r - l + 1);
}
for(register int i = 1;i <= m;++i)
{
diff[i] += diff[i - 1];
ans[i] += diff[i];
}
for(register int i = 1;i <= m;++i)
{
ans[i] += ans[i - 1];
printf("%lld ",1ll * i * (m - i + 1) - ans[i]);
}
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡