题解
将 x坐标相同的点连接到一起,将 y坐标相同的点连接到一起,每个联通块的 x、y坐标的种类的乘积的和就是答案。
对于第 i个联通块(集合),用 nx[i]表示其中 x坐标的种类数, ny[i]表示其中 y坐标的种类数, nx[i]∗ny[i]就是这个集合的贡献
我们将 x、y坐标当做点,当一个新点加入时,将 x[i]与 y[i]合并,同时修改这个集合的 nx和 ny的大小,如下图
这里将点抽象成为一种连接两点的父子关系。点的加入意味着两个集合的合并。我们在合并时就可以更新答案。
但是,这道题涉及点的消失的问题,就意味着之前建立的关系可能需要回滚。
这里,我们以时间轴建立线段树,统计出每一个点在图上出现的时间段,插入到线段树中。
在线段树中,往下层走,意味着新的点的加入,向上层走,就进行回滚操作。如果左右边界相等,就意味着到一个独立的时间点了,这一时间的答案就知道了。
代码
#include<bits/stdc++.h>
#define N 600010
#define INF 0x3f3f3f3f
#define eps 1e-10
// #define pi 3.141592653589793
#define P 1000000007
#define LL long long
#define pb push_back
#define fi first
#define se second
#define cl clear
#define si size
#define lb lower_bound
#define ub upper_bound
#define mem(x) memset(x,0,sizeof x)
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/priority_queue.hpp>
using namespace __gnu_pbds;
typedef pair<int,int> pi;
typedef pair<int,pi> pp;
typedef __gnu_pbds::priority_queue<pp,greater<pp> > heap;
map<pi,int> mp;
vector<pi> a[N<<1];
LL nx[N],ny[N],sz[N],ans[N],fa[N],res;
pi st[N];
int op=0;
int getfa(int x){
return(fa[x]==x?x:getfa(fa[x]));
}
void ins(int x,int fl,int fr,int l,int r,pi t){
if (l==fl && fr==r) a[x].pb(t);else
{
int mid=l+r>>1;
if (fr<=mid) ins(x<<1,fl,fr,l,mid,t);else
if (fl>mid) ins(x<<1|1,fl,fr,mid+1,r,t);else{
ins(x<<1,fl,mid,l,mid,t);
ins(x<<1|1,mid+1,fr,mid+1,r,t);
}
}
}
void spy(int x,int l,int r){
int tm=op;
for (auto i:a[x]){
int x=getfa(i.fi),y=getfa(i.se);
if (x!=y){
if (sz[x]<sz[y]) swap(x,y);
st[++op]=pi(x,y);
fa[y]=x;
res-=nx[x]*ny[x]+nx[y]*ny[y];
sz[x]+=sz[y]; nx[x]+=nx[y]; ny[x]+=ny[y];
res+=nx[x]*ny[x];
}
}
if (l==r) ans[l]=res;else{
spy(x<<1,l,l+r>>1);
spy(x<<1|1,(l+r>>1)+1,r);
}
while(tm!=op){
int x=st[op].fi,y=st[op--].se;
res-=nx[x]*ny[x];
sz[x]-=sz[y]; nx[x]-=nx[y]; ny[x]-=ny[y];
res+=nx[x]*ny[x]+nx[y]*ny[y];
fa[y]=y;
}
}
int main()
{
int n;
sc(n);
for (int i=1,x,y;i<=n;i++){
scc(x,y); y+=3e5;
if(mp[pi(x,y)]){
ins(1,mp[pi(x,y)],i-1,1,n,pi(x,y));
mp.erase(pi(x,y));
}else mp[pi(x,y)]=i;
}
for (auto i:mp) ins(1,i.se,n,1,n,i.fi);
for (int i=1;i<=6e5;i++) (i<=3e5?nx:ny)[i]=sz[i]=1,fa[i]=i;
spy(1,1,n);
printf("%lld",ans[1]);
for (int i=2;i<=n;i++) printf(" %lld",ans[i]);
}