cf1140f Extending Set of Points
题目大意:每次给你一个点,如果这个点已经存在, 那么就删除这个点,如果这个点不存在,那么就加入这个点。每次询问当前集合的扩展集合中点的个数。
扩展集合是这么得到的,如果当前集合中存在矩形的3个点,那么第4个点就会被放到扩展集合中,不断这样拓展。
思路: 首先我们要建图,横坐标相同的点连一条边,纵坐标相同的点连一条边,这样就组成了若干个联通块。我们统计每一个联通块里面不同的横坐标数量和纵坐标数量。他们数量的乘就是最终这个联通里面点的数量。 我们可以用并查集来维护这个过程。
注意这里要列点以后才能用并查集,把每个点看成是一条边,列成2个点,每个y+300000,然后建图,并查集统计的时候要统计x个数和y个数。
由于这题还有删除操作,而并查是不支持删除操作的,所以我们要考虑每个点有效的一个时间范围,比如(1,2)在第1个询问到第8个询问有效,那么就把(1,2)插入到1-8这个区间,用线段树维护,这样每个区间最多会产生,$log(q)$次修改。
然后我们dfs去遍历每个点,每到一个点,就把这个点(区间)对应的点全部放到并查及里面,当退出这个递归的时候,要恢复并查及,所以这个并查及不能进行路径压缩,但是我们要有保证深度,所以我们需要启发式合并。
最终的时间复杂度:$O(q*(log(q))^2)$。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define rep(i,a,b) for(int i=a;i<=b;i++) 4 #define Rep(i,a,b) for(int i=a;i>=b;i--) 5 #define ms(i,a) memset(a,i,sizeof(a)) 6 #define gc() getchar() 7 #define mid (l+r>>1) 8 #define lc (x<<1) 9 #define rc (x<<1|1) 10 #define pii pair<int,int> 11 #define mp make_pair 12 #define fi first 13 #define se second 14 #define LL long long 15 template<class T>void read(T &x){ 16 x=0; char c=0; 17 while (!isdigit(c)) c=gc(); 18 while (isdigit(c)) x=x*10+(c^48),c=gc(); 19 } 20 int const N=300000+3; 21 map<pii,int>mat; 22 vector<pii >a[N<<2]; 23 map<pii,int> :: iterator it; 24 int n,f[N<<1],sz[N<<1],cntx[N<<1],cnty[N<<1]; 25 LL ans[N],now; 26 int find(int x){return x==f[x]? x: find(f[x]); } 27 void update(int x,int l,int r,int ll,int rr,pii t){ 28 if(ll<=l && r<=rr) { 29 a[x].push_back(t); 30 return; 31 } 32 if(ll<=mid) update(lc,l,mid,ll,rr,t); 33 if(rr>mid) update(rc,mid+1,r,ll,rr,t); 34 } 35 void merge(int x,int y,stack<pii> & st){ 36 int fx=find(x); 37 int fy=find(y); 38 if(fx!=fy){ 39 if(sz[fx]<sz[fy]) swap(fx,fy); 40 now-=1LL*cntx[fx]*cnty[fx]; 41 now-=1LL*cntx[fy]*cnty[fy]; 42 f[fy]=fx; 43 sz[fx]+=sz[fy]; 44 cntx[fx]+=cntx[fy]; 45 cnty[fx]+=cnty[fy]; 46 now+=1LL*cntx[fx]*cnty[fx]; 47 st.push(mp(fx,fy)); 48 } 49 } 50 void del(stack<pii> &st){ 51 while (!st.empty()){ 52 int fx=st.top().fi; 53 int fy=st.top().se; 54 st.pop(); 55 now-=1LL*cntx[fx]*cnty[fx]; 56 f[fy]=fy; 57 cntx[fx]-=cntx[fy]; 58 cnty[fx]-=cnty[fy]; 59 sz[fx]-=sz[fy]; 60 now+=1LL*cntx[fx]*cnty[fx]; 61 now+=1LL*cntx[fy]*cnty[fy]; 62 } 63 } 64 void dfs(int x,int l,int r){ 65 66 stack<pii>st; 67 for(int i=0;i<a[x].size();i++) merge(a[x][i].fi,a[x][i].se,st); 68 if(l==r){ 69 ans[l]=now; 70 del(st); 71 return ; 72 } 73 dfs(lc,l,mid); 74 dfs(rc,mid+1,r); 75 del(st); 76 } 77 78 int main(){ 79 read(n); 80 rep(i,1,n){ 81 int x,y; 82 read(x); read(y); 83 y+=300000; 84 if(mat.find(mp(x,y))==mat.end()) mat[mp(x,y)]=i; 85 else { 86 update(1,1,n,mat[mp(x,y)],i-1,mp(x,y)); 87 mat.erase(mp(x,y)); 88 } 89 } 90 for(it=mat.begin();it!=mat.end();it++){ 91 pii t=it->fi; 92 int g=it->se; 93 update(1,1,n,g,n,t); 94 } 95 rep(i,1,300000) f[i]=i,sz[i]=1,cntx[i]=1; 96 rep(i,300000+1,600000) f[i]=i,sz[i]=1,cnty[i]=1; 97 dfs(1,1,n); 98 rep(i,1,n) printf("%lld ",ans[i]); 99 return 0; 100 }