题目大意
(n)个点,(m)条边,对每条边进行编号,若编号为([l,r])的区间内出现了环,则给每一条边的(val)加(1),最后输出每条边的(val)。
大体思路
注意到:若([l,r])之间存在环,则区间([l,r])到区间([l,m])都包含有环。
再整理一下得到:
-
给区间([l,r])中的边,每条边的(val)都加上"(m-r+1)"
-
给区间([r+1,m])中的边,加上一个首相为"(m-r)",公差为"(-1)"的等差数列。
这个显然可以用二维差分得到。
那么现在的问题就是:如何找到又环的区间?
很简单,我们可以用双指针,因为随着 (l) 的增大,(r) 必然不会减小。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=400005;
struct edge{
int u,v;
} e[N];
ll delta1[N],delta2[N];
int val[N],fa[N],rev[N],ch[N][2];
int m,q,opt;
int wh(int x){return ch[fa[x]][1]==x;}
bool isrt(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
void rever(int x){rev[x]^=1,swap(ch[x][0],ch[x][1]);}
void pushdown(int x){
if (rev[x]){
if (ch[x][0]) rever(ch[x][0]);
if (ch[x][1]) rever(ch[x][1]);
rev[x]=0;
}
}
void Allpushdown(int x){
if (!isrt(x)) Allpushdown(fa[x]);
pushdown(x);
}
void rotate(int x){
int y=fa[x],z=fa[y],c=wh(x);
if (!isrt(y)) ch[z][wh(y)]=x;
fa[x]=z;
ch[y][c]=ch[x][c^1];
fa[ch[y][c]]=y;
ch[x][c^1]=y;
fa[y]=x;
}
void splay(int x){
Allpushdown(x);
for (;!isrt(x);rotate(x))
if (!isrt(fa[x])) rotate(wh(fa[x])==wh(x)?fa[x]:x);
}
void access(int x){
for (int y=0;x;y=x,x=fa[x]) splay(x),ch[x][1]=y;
}
void makert(int x){
access(x),splay(x),rever(x);
}
int findrt(int x){
access(x),splay(x);
while (ch[x][0]) pushdown(x),x=ch[x][0];
splay(x);
return x;
}
void link(int x,int y){
makert(x),fa[x]=y;
}
void cut(int x,int y){
makert(x),access(y),splay(y);
if (ch[y][0]!=x&&!ch[ch[y][0]][1]) return;
fa[x]=ch[y][0]=0;
}
void query(int x,int y){
makert(x),access(y),splay(y);
}
void solve(int l,int r,ll head,ll delta){
if (l>r) return;
delta1[l]+=head;
delta1[r+1]+=-head;
delta2[l+1]+=delta;
delta2[r+1]+=-delta;
}
int main(){
scanf("%d",&m);
for (int i=1;i<=m;i++) scanf("%d%d",&e[i].u,&e[i].v);
int r=1;
for (int l=1;l<=m;l++){
while (r<=m){
int u=e[r].u,v=e[r].v;
if (findrt(u)==findrt(v)){
solve(l,r,m-r+1,0);
solve(r+1,m,m-r,-1);
break;
} else link(u,v);
++r;
}
cut(e[l].u,e[l].v);
}
ll x=0,y=0;
for (int i=1;i<=m;i++){
x+=delta1[i],y+=delta2[i],x+=y;
printf("%lld ",x);
}
puts("");
return 0;
}