题意简化一下平面上有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();
}