题意简化一下平面上有n个点(n<=100000,坐标<=一百万),两种操作,一种是选两点连边,二是问在某一y坐标上有几个联通块,以及这些联通块连接了多少个点
总体思路是并查集+线段树,在并查集合并时维护线段树。开两棵线段树,一颗维护每个y坐标上的联通块上的点数目,一颗维护每个y坐标上的联通块数目
注意这个题每个点的x坐标对答案没有影响,所以只记录一下高度就可以了
并查集维护四个量,父亲,以此为根的联通块点数目,联通块的最大高度,联通块的最小高度
代码中把f1设为最大高度靠上的,分三种情况讨论
本来以为数据100万能卡过去,离散化完了也是十万多,就懒得没有离散化
没想到不离散化会T,中间还有一次离散化出锅了
//本来以为数据100万能卡过去,离散化完了也是十万多,就懒得没有离散化 //没想到不离散化会T,中间还有一次离散化出锅了 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define MAXN (200010) #define ls ((rt<<1)+1) #define rs ((rt<<1)+2) #define mid ((l+r)>>1) #define fr(i,s,t) for (i=s;i<=t;i++) #define Cl(a) memset(a,0,sizeof(a)) using namespace std; int n,H[MAXN],Min[MAXN],Max[MAXN],m,fa[MAXN],sum[MAXN],Up,temp[MAXN]; char S[200]; int fin(int x){ if (fa[x]==x) return x; fa[x]=fin(fa[x]); return fa[x]; } struct Order{ int opt,x,y; void Read(){ scanf("%s",S); if (S[0]=='r') opt=1; if (opt==1) scanf("%d %d",&x,&y); else{ double d; scanf("%lf",&d); x=d; x++; } } }O[MAXN]; struct Tree{ int T[MAXN*5]; void Clear(){ memset(T,0,sizeof(T)); } void update(int rt,int l,int r,int L,int R,int val){ if (L>R) return; if (l>=L&&r<=R){ T[rt]+=val; return; } if (L<=mid) update(ls,l,mid,L,R,val); if (R>mid) update(rs,mid+1,r,L,R,val); } int Query(int rt,int l,int r,int pos){ int res=0; res+=T[rt]; if (l==r) return res; if (pos<=mid) return res+Query(ls,l,mid,pos); else return res+Query(rs,mid+1,r,pos); } }T[2]; void Merge(int x,int y){ int f1=fin(x),f2=fin(y); if (f1==f2) return; if (Max[f1]<Max[f2]) swap(f1,f2),swap(x,y); //1 if (Min[f1]>Max[f2]){ T[1].update(0,1,Up,Min[f1],Max[f1]-1,-sum[f1]); T[1].update(0,1,Up,Min[f2],Max[f2]-1,-sum[f2]); fa[f2]=f1; sum[f1]+=sum[f2]; T[1].update(0,1,Up,Min[f2],Max[f1]-1,sum[f1]); T[0].update(0,1,Up,Max[f2],Min[f1]-1,1); Min[f1]=Min[f2]; return; } //2 if (Min[f2]>=Min[f1]){ T[0].update(0,1,Up,Min[f2],Max[f2]-1,-1); T[1].update(0,1,Up,Max[f2],Max[f1]-1,sum[f2]); T[1].update(0,1,Up,Min[f1],Min[f2]-1,sum[f2]); fa[f2]=f1; sum[f1]+=sum[f2]; return; } //3 T[0].update(0,1,Up,Min[f1],Max[f2]-1,-1); T[1].update(0,1,Up,Max[f2],Max[f1]-1,sum[f2]); T[1].update(0,1,Up,Min[f2],Min[f1]-1,sum[f1]); fa[f2]=f1; sum[f1]+=sum[f2]; Min[f1]=Min[f2]; } void lsh(){ memset(temp,0,sizeof(temp)); int i,k=0; for (i=1;i<=n;i++) temp[++k]=H[i]; for (i=1;i<=m;i++) if (O[i].opt!=1) temp[++k]=O[i].x; sort(temp+1,temp+k+1); Up=unique(temp+1,temp+k+1)-temp-1; fr(i,1,n) H[i]=lower_bound(temp+1,temp+Up+1,H[i])-temp; fr(i,1,m) if (O[i].opt!=1) O[i].x=lower_bound(temp+1,temp+Up+1,O[i].x)-temp; } void Work(){ Cl(H); Cl(fa); Cl(Min); Cl(Max); Cl(sum); Cl(O); Cl(T); Up=0; scanf("%d",&n); int i,x,y; fr(i,1,n) scanf("%d %d",&x,&H[i]),H[i]++; scanf("%d",&m); fr(i,1,m) O[i].Read(); lsh(); fr(i,1,n) fa[i]=i,Min[i]=Max[i]=H[i],sum[i]=1; for (i=1;i<=m;i++){ int opt=O[i].opt; if (opt==1) x=O[i].x,y=O[i].y,Merge(x+1,y+1); else{ x=O[i].x; printf("%d %d\n",T[0].Query(0,1,Up,x),T[1].Query(0,1,Up,x)); } } } int main(){ int T_Num; cin>>T_Num; while (T_Num--) Work(); }