题意:
给出一个笛卡尔坐标系中左下角坐标为 ,右上角坐标为 的矩形,有 条射线,起点在矩形内部,其坐标为 ,方向为上/下/左/右( ,且 。( )
问矩形一共被分成多少块?
分析:
欧拉图论定理:
如果一个 联通平面图 有 个顶点、 条边、 个面,那么
①顶点个数 :
- 矩阵原顶点: 个
- 矩阵边界与射线交点: 个
- 射线起点: 个
- 射线之间的交点: 个
②边数 (即线段个数):
一条线段每多一个交点,就会被多分割出一条线段。
- 矩形边界上线段个数:
- 射线上线段个数: (每个交点都同时存在于 条射线上)
所以根据公式: ,可以得到平面内总分块数 ,除去矩形外的无穷大区块,得到 。
于是问题就转化成了求射线的交点个数 ,离散化后用线段树/树状数组求解即可。
以下代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+50;
int n,m,K;
int X[maxn],Y[maxn];
struct ray
{
int x,y;
char dir;
}r[maxn];
bool cmp(const ray &a,const ray &b)
{
return a.x<b.x;
}
void init()
{
sort(X+1,X+K+1);
sort(Y+1,Y+K+1);
for(int i=1;i<=K;i++)
{
r[i].x=lower_bound(X+1,X+K+1,r[i].x)-X;
r[i].y=lower_bound(Y+1,Y+K+1,r[i].y)-Y;
}
}
int t[maxn<<2];
void updata(int rt,int l,int r,int val)
{
if(l==r)
{
t[rt]++;
return;
}
int mid=(l+r)>>1;
if(val<=mid)
updata(rt<<1,l,mid,val);
else
updata(rt<<1|1,mid+1,r,val);
t[rt]=t[rt<<1]+t[rt<<1|1];
}
int query(int rt,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr)
return t[rt];
int res=0;
int mid=(l+r)>>1;
if(ql<=mid)
res+=query(rt<<1,l,mid,ql,qr);
if(qr>mid)
res+=query(rt<<1|1,mid+1,r,ql,qr);
return res;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d %d %d",&n,&m,&K);
for(int i=1;i<=K;i++)
{
scanf("%d %d",&r[i].x,&r[i].y);
getchar();
r[i].dir=getchar();
X[i]=r[i].x;
Y[i]=r[i].y;
}
init();
sort(r+1,r+K+1,cmp);
int ans=0;
memset(t,0,sizeof(t));
for(int i=1;i<=K;i++)
{
int x=r[i].x,y=r[i].y;
if(r[i].dir=='R')
updata(1,1,K,y);
else if(r[i].dir=='U')
ans+=query(1,1,K,y,K);
else if(r[i].dir=='D')
ans+=query(1,1,K,1,y);
}
memset(t,0,sizeof(t));
for(int i=K;i>=1;i--)
{
int x=r[i].x,y=r[i].y;
if(r[i].dir=='L')
updata(1,1,K,y);
else if(r[i].dir=='U')
ans+=query(1,1,K,y,K);
else if(r[i].dir=='D')
ans+=query(1,1,K,1,y);
}
printf("%d\n",ans+1);
}
return 0;
}