王国LA4730

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



猜你喜欢

转载自blog.csdn.net/lerbon23james/article/details/79808001
LA
今日推荐