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);//关闭重定向输出
}