CodeForces 1401E Divide Square (线段树)

There is a square of size 106×106106×106 on the coordinate plane with four points (0,0)(0,0), (0,106)(0,106), (106,0)(106,0), and (106,106)(106,106) as its vertices.

You are going to draw segments on the plane. All segments are either horizontal or vertical and intersect with at least one side of the square.

Now you are wondering how many pieces this square divides into after drawing all segments. Write a program calculating the number of pieces of the square.

Input

The first line contains two integers nn and mm (0≤n,m≤1050≤n,m≤105) — the number of horizontal segments and the number of vertical segments.

The next nn lines contain descriptions of the horizontal segments. The ii-th line contains three integers yiyi, lxilxi and rxirxi (0<yi<1060<yi<106; 0≤lxi<rxi≤1060≤lxi<rxi≤106), which means the segment connects (lxi,yi)(lxi,yi) and (rxi,yi)(rxi,yi).

The next mm lines contain descriptions of the vertical segments. The ii-th line contains three integers xixi, lyilyi and ryiryi (0<xi<1060<xi<106; 0≤lyi<ryi≤1060≤lyi<ryi≤106), which means the segment connects (xi,lyi)(xi,lyi) and (xi,ryi)(xi,ryi).

It's guaranteed that there are no two segments on the same line, and each segment intersects with at least one of square's sides.

Output

Print the number of pieces the square is divided into after drawing all the segments.

Example

input

Copy

3 3
2 3 1000000
4 0 4
3 0 1000000
4 0 1
2 0 5
3 1 1000000

output

Copy

7

Note

The sample is like this:

 

题解:只有两种情况会导致分块数增加。(1)一条线连接正方形两条边,导致分块数+1.(2)任意两条线相交一次(不包括边界),分块数+1。问题转化为求垂直线和水平线的交点个数。

分两种情况,一种是垂直线从下边界射出,另一种是垂直线从上边界射出。

对于第一种情况,我们从下往上扫描边,可以通过以水平线的纵坐标为关键字排序,下边界射出的线段同理,按照纵坐标从下往上依次扫描。我们用线段树统计每个横坐标被覆盖的次数。扫描到水平线时,就将水平线覆盖的区域+1。扫描到垂直线时,对垂直线所在的横坐标做单点查询。注意当水平线和垂直线高度相同时,先处理水平线。

对于第二种情况同理,我们重新建树,从上往下扫描边,一样的操作。

最终答案是连接正方形两边的线段数+垂直线和水平线的交点数

注意使用long long

代码:

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<string.h>
using namespace std;
const int maxn=1000000;
struct Edge{long long  k,l,r;};
Edge a[maxn],b[maxn],s1[maxn],s2[maxn];

int tree[maxn*6][3];
int lazy[maxn*6];

int comp(Edge a,Edge b){return a.k<b.k;}
int comp1(Edge a,Edge b){return a.r<b.r;}
int comp2(Edge a,Edge b){return a.l<b.l;}
void build(int x)
{
	int l,r,mid;
	l=tree[x][0];r=tree[x][1];
	if (l==r) return;
	mid=(l+r)/2;
	tree[x+x][0]=l;tree[x+x][1]=mid;
	tree[x+x+1][0]=mid+1;tree[x+x+1][1]=r;
	build(x+x);
	build(x+x+1);	
}

void down(int x)
{
	if (tree[x][0]==tree[x][1])
	{
		lazy[x]=0;
		return;
	}
	tree[x+x][2]+=lazy[x]; lazy[x+x]+=lazy[x];
	tree[x+x+1][2]+=lazy[x]; lazy[x+x+1]+=lazy[x];
	lazy[x]=0;
}

void add(int x,int l,int r)
{
	down(x);
	if ((tree[x][0]==l)&&(tree[x][1]==r))
	{
		tree[x][2]+=1;
		lazy[x]+=1;
		return;
	}
	int mid=(tree[x][0]+tree[x][1])/2;
	if (r<=mid) add(x+x,l,r);
	else if (l>mid) add(x+x+1,l,r);
	else
	{
		add(x+x,l,mid);
		add(x+x+1,mid+1,r);
	}
}

int get(int x,int y)
{
	down(x);
	if ((tree[x][0]==tree[x][1])&&(tree[x][0]==y))
	{
		return tree[x][2];
	}
	int mid=(tree[x][0]+tree[x][1])/2;
	if (y<=mid) return(get(x+x,y));
	else return(get(x+x+1,y));
}

int main()
{
	//freopen("data.in","r",stdin); //输入重定向,输入数据将从in.txt文件中读取 
//	freopen("a.txt","w",stdout); //输出重定向,输出数据将保存out.txt文件中 

	tree[1][0]=0;tree[1][1]=1000000;
	build(1);
	int n,m;
	long long ans=1,sum1=0,sum2=0;
	cin>>n>>m;
	for (int i=1;i<=n;i++)
	{
		cin>>a[i].k>>a[i].l>>a[i].r;
		if ((a[i].l==0)&&(a[i].r==1000000)) ans+=1;
	}
	sort(a+1,a+n+1,comp);
	for (int i=1;i<=m;i++)
	{
		cin>>b[i].k>>b[i].l>>b[i].r;
		if ((b[i].l==0)&&(b[i].r==1000000)) ans+=1;
		if (b[i].l==0) 
		{
			sum1++;
			s1[sum1]=b[i];
		}
		else if (b[i].r=1000000)
		{
			sum2++;
			s2[sum2]=b[i];
		}
	}
	sort(s1+1,s1+1+sum1,comp1);
	sort(s2+1,s2+1+sum2,comp2);
	int i=1,j=1;
	while (true)
	{
		if (((a[i].k<=s1[j].r)||(j>sum1))&&(i<=n))
		{
			add(1,a[i].l,a[i].r);
			i+=1;
		}
		else if (((a[i].k>s1[j].r)||(i>n))&&(j<=sum1))
		{
			ans+=get(1,s1[j].k);
			j+=1; 
		}
		if ((i>n)&&(j>sum1)) break;
	}
	i=n;j=sum2;
	memset(tree,0,sizeof(tree));
	memset(lazy,0,sizeof(lazy));
	tree[1][0]=0;tree[1][1]=1000000;
	build(1);
	while (true)
	{
		if (((a[i].k>=s2[j].l)||(j<1))&&(i>=1))
		{
			add(1,a[i].l,a[i].r);
			i-=1;
		}
		else if (((a[i].k<s2[j].l)||(i<1))&&(j>0))
		{
			ans+=get(1,s2[j].k);
			j-=1; 
		}
		if ((i<1)&&(j<1)) break;
	}
	cout<<ans;
//	fclose(stdin);//关闭重定向输入
//	fclose(stdout);//关闭重定向输出 

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值