[CSP-S模拟测试]:building(模拟)

题目传送门(内部题64)


输入格式

第一行有一个整数$id$,表示测试点编号。第二行有四个整数$n,m,k,q$。
而后有$k$行,每一行有四个整数$x_{i_1},y_{i_1},x_{i_2},y_{i_2}$。而后有$q$行,每一行有两个整数$u_i,v_i$。
html


输出格式

有$q$行,每一行一个整数表示答案。c++


样例

样例输入:算法

1
5 5 6 10
1 1 1 2
3 2 3 4
5 2 5 5
2 1 3 1
1 4 2 4
4 5 4 5
0 1
0 2
0 3
0 4
0 5
1 1
1 2
1 3
1 4
1 5
测试

样例输出:spa

3
5
9
11
16
2
2
1
2
1
3d


数据范围与提示

对于全部数据,$1\leqslant id\leqslant 20$,$n,m,k\leqslant 10^5$,$q\leqslant 2n$,$1\leqslant x_{i_1}\leqslant x_{i_2}\leqslant n$,$1\leqslant y_{i_1}\leqslant y_{i_2}\leqslant m$,$u_i\in\{0,1\}$,$v_i\leqslant n$。htm


题解

又没有打正解,是由于没看懂题解(我太菜辣)。blog

咱们先来考虑$u=0$的状况,也就是咱们只须要求出楼盘总数。排序

能够用前缀和轻松解决。get

那么再来考虑$u=1$的状况,不重叠这个性质超级棒!

先只考虑$x_{i_1}=x_{i_2}$的状况,咱们将其按$x$为第一维排序,$y$为第二维排序,而后首先判断其与前面一个有没有联通,在判断其与上一行有没有联通,大体能够分为如下四种状况$\downarrow$

你可能以为,若是有两个相邻,我就将块数$--$,可是这样是错的,好比下图中的状况$\downarrow$

而后你就去世了……

由于咱们在考虑最下面的$4$的时候发现它与$2$和$3$都相邻,可是$2$与$3$都与$1$联通,考虑的时候就已经在一个联通块里了。

不用担忧,并查集维护一下就好啦~

下面在来考虑通常状况,为方便,忽略一些能够能够归为一类的状况,将其大体分为一下四种状况$\downarrow$

第一种状况上面已经讨论了,下面来看其它状况。

咱们能够开两个$vector$,分别记录每一行和每一列有哪一个矩形的$(x_{i_2},y_{i_2})$,由于本题保证了没有重叠,因此只用记录$(x_{i_2},y_{i_2})$,处理每个矩行的时候暴力扫一遍上一行的$vector$和相邻列的$vector$,为何须要扫相邻两列的$vector$而不是只扫左边这一列的,由于会出现下面这种状况$\downarrow$

咱们在扫到红线这一行的时候尚未扫到最下面的矩形,因此两侧的矩形还不能合并到一块儿,而咱们在扫到最下面一行的矩形的时候才须要合并两侧的矩形。

而对于行,咱们则不用考虑这个问题,这就是上面行只用扫上面一行,而列则要扫相邻两列的缘由。

有了这些,就是疯狂的调代码了,建议现将$\forall1\leqslant i\leqslant k,x_{i_1}=x_{i_2}$的部分分拿到再冲击正解,由于这个部分分的思想很重要。

虽然说个人算法会被极限数据卡成$\Theta(n^2)$,可是随机数据基本上是线性的。

时间复杂度:$\Theta($玄学$)$。

指望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
struct rec{int x0,x2,y0,y2;}e[100001];
int id,n,m,k,q,u,v;
int fa[100001];
long long s1[100001],s2[100001];
vector<int> vec[100002],vet[100002];
bool cmp(rec a,rec b){return a.x0==b.x0?a.y0<b.y0:a.x0<b.x0;}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int main()
{
	scanf("%d%d%d%d%d",&id,&n,&m,&k,&q);
	for(int i=1;i<=k;i++)
		scanf("%d%d%d%d",&e[i].x0,&e[i].y0,&e[i].x2,&e[i].y2);
	sort(e+1,e+k+1,cmp);
	for(int i=1;i<=k;i++)
	{
		vec[e[i].y2].push_back(i);
		vet[e[i].x2].push_back(i);
		fa[i]=i;
	}
	long long sum=0;
	for(int i=1;i<=k;i++)
	{
		if(e[i].x0==e[i].x2){s1[e[i].x0]+=e[i].y2-e[i].y0+1;s1[e[i].x0+1]-=e[i].y2-e[i].y0+1;}
		else{s1[e[i].x0]++;s1[e[i].x2+1]--;}
		if(e[i].x0!=e[i-1].x0)for(int j=e[i-1].x0;j<e[i].x0;j++)s2[j]=sum;
		sum++;
		for(int j=0;j<vet[e[i].x0-1].size();j++)
		{
			int x=find(i);
			int y=find(vet[e[i].x0-1][j]);
			if(x==y)continue;
			if((e[vet[e[i].x0-1][j]].y0<=e[i].y0&&e[i].y0<=e[vet[e[i].x0-1][j]].y2)||(e[i].y0<=e[vet[e[i].x0-1][j]].y0&&e[vet[e[i].x0-1][j]].y0<=e[i].y2))
			{
				sum--;
				fa[x]=y;
			}
		}
		for(int j=0;j<vec[e[i].y0-1].size();j++)
		{
			if(e[vec[e[i].y0-1][j]].x0>e[i].x0)continue;
			int x=find(i);
			int y=find(vec[e[i].y0-1][j]);
			if(x==y)continue;
			if((e[vec[e[i].y0-1][j]].x0<=e[i].x0&&e[i].x0<=e[vec[e[i].y0-1][j]].x2)||(e[i].x0<=e[vec[e[i].y0-1][j]].x0&&e[vec[e[i].y0-1][j]].x0<=e[i].x2))
			{
				sum--;
				fa[x]=y;
			}
		}
		for(int j=0;j<vec[e[i].y2+1].size();j++)
		{
			if(e[vec[e[i].y2+1][j]].x0>e[i].x0)continue;
			int x=find(i);
			int y=find(vec[e[i].y2+1][j]);
			if(x==y)continue;
			if((e[vec[e[i].y2+1][j]].x0<=e[i].x0&&e[i].x0<=e[vec[e[i].y2+1][j]].x2)||(e[i].x0<=e[vec[e[i].y2+1][j]].x0&&e[vec[e[i].y2+1][j]].x0<=e[i].x2))
			{
				sum--;
				fa[x]=y;
			}
		}
	}
	for(int i=e[k].x0;i<=n;i++)s2[i]=sum;
	for(int i=1;i<=n;i++)s1[i]+=s1[i-1];
	for(int i=1;i<=n;i++)s1[i]+=s1[i-1];
	while(q--)
	{
		scanf("%d%d",&u,&v);
		if(u)printf("%lld\n",s2[v]);
		else printf("%lld\n",s1[v]);
	}
	return 0;
}

rp++

相关文章
相关标签/搜索