[CF1140F] Extending Set of Points
相当套路而巧妙的构造。
假如我们对于横纵坐标构造二分图,然后用如下方法连边:
- 对于点 \((x,y)\),连接 \(x,y\)。
那么对于一个有 \(num_x\) 个横坐标点和 \(num_y\) 个纵坐标点的连通块,它所产生的贡献就是 \(num_x\times num_y\)。
这玩意儿需要联通块和删除,考虑线段树分治 \(+\) 可持久化并查集。
时间复杂度 \(O(n\log^2n)\)。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=6e5+5;
struct ed{int x,y;};
bool operator<(ed x,ed y){
return (x.x!=y.x)?x.x<y.x:x.y<y.y;
}set<ed>st;vector<ed>g[4*N];
int n,ans,fa[N],sz[N],sx[N];
unordered_map<int,int>mp[N];
struct mer{
int sz,sx,x,y;
};stack<mer>sk;
inline void init(){
for(int i=1;i<=6e5;i++)
fa[i]=i,sz[i]=1,sx[i]=(i<=3e5);
}inline int find(int x){
return fa[x]==x?x:find(fa[x]);
}inline void unite(int x,int y){
x=find(x),y=find(y);
if(x==y) return;
if(sz[x]<sz[y]) swap(x,y);
sk.push({sz[x],sx[x],x,y});
ans-=(sz[x]-sx[x])*sx[x];
ans-=(sz[y]-sx[y])*sx[y];
fa[y]=x,sz[x]+=sz[y],sx[x]+=sx[y];
ans+=(sz[x]-sx[x])*sx[x];
}inline void chg(int x,int l,int r,int L,int R,ed e){
if(L>R) return;
if(L<=l&&r<=R){
g[x].push_back(e);
return;
}int mid=(l+r)/2;
if(L<=mid) chg(x*2,l,mid,L,R,e);
if(R>mid) chg(x*2+1,mid+1,r,L,R,e);
}inline void solve(int x,int l,int r){
int ltp=sk.size();
for(auto e:g[x]) unite(e.x,e.y);
int mid=(l+r)/2;if(l==r) cout<<ans<<" ";
else solve(x*2,l,mid),solve(x*2+1,mid+1,r);
while(sk.size()>ltp){
mer x=sk.top();sk.pop();
ans-=(sz[x.x]-sx[x.x])*sx[x.x];
fa[x.y]=x.y,sz[x.x]=x.sz,sx[x.x]=x.sx;
ans+=(sz[x.x]-sx[x.x])*sx[x.x];
ans+=(sz[x.y]-sx[x.y])*sx[x.y];
}
}signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n,init();
for(int i=1,x,y;i<=n;i++){
cin>>x>>y;
if(mp[x][y]){
chg(1,1,n,mp[x][y],i-1,{x,y+3e5});
mp[x][y]=0,st.erase({x,y});
}else mp[x][y]=i,st.insert({x,y});
}for(auto x:st)
chg(1,1,n,mp[x.x][x.y],n,{x.x,x.y+3e5});
solve(1,1,n);
return 0;
}

浙公网安备 33010602011771号