在n*m的坐标系平面上有k条射线,射线有上下左右四种不同的方向,
问这些射线把这个平面切成多少块?
坐标系的左下角为(0,0),右上角为(n,m).
数据范围:n,m<=1e9,k<=1e5,保证不存在一条射线直接将矩形切成两块的情况
答案就是交点个数+1
那么对于每条横线,计算出有多少条竖线穿过就行
用线段树扫描线的思想,将射线拆分为修改和询问.
用竖着的扫描线从x=0向右扫:
1.遇到横线的左端点就加入线段树,
2.遇到横线的右端点就消除,
3.遇到竖线就统计线段树中有多少个点和这个竖线相交
线段树大小和纵坐标范围有关,因此对纵坐标离散化.
#include
using namespace std;
const int maxm=1e5+5;
int a[maxm<<2];
int b[maxm];
int n,m,k;
//
struct Node{
int x,y1,y2,op;
bool operator<(const Node& a)const{
if(x!=a.x)return x<a.x;
return op<a.op;
}
}e[maxm<<2];
//
void init(int l,int r,int node){//清空树
a[node]=0;
if(l==r)return ;
int mid=(l+r)/2;
init(l,mid,node*2);
init(mid+1,r,node*2+1);
}
void update(int x,int val,int l,int r,int node){
if(l==r){
a[node]+=val;
return ;
}
int mid=(l+r)/2;
if(x<=mid)update(x,val,l,mid,node*2);
else update(x,val,mid+1,r,node*2+1);
a[node]=a[node*2]+a[node*2+1];
}
int ask(int st,int ed,int l,int r,int node){
if(st<=l&&ed>=r)return a[node];
int mid=(l+r)/2;
int ans=0;
if(st<=mid)ans+=ask(st,ed,l,mid,node*2);
if(ed>mid)ans+=ask(st,ed,mid+1,r,node*2+1);
return ans;
}
signed main(){
int T;scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&m,&k);
int tot=0;
int num=0;
for(int i=1;i<=k;i++){
int x,y;char s[2];
scanf("%d%d%s",&x,&y,s);
b[++num]=y;
if(s[0]=='L'){
e[++tot]={0,y,0,1};
e[++tot]={x+1,y,0,2};
}else if(s[0]=='R'){
e[++tot]={x,y,0,1};
e[++tot]={n+1,y,0,2};
}else if(s[0]=='U'){
e[++tot]={x,y,m,3};
}else if(s[0]=='D'){
e[++tot]={x,0,y,3};
}
}
b[++num]=0,b[++num]=m;
sort(e+1,e+1+tot);
sort(b+1,b+1+num);
num=unique(b+1,b+1+k+2)-b-1;
init(1,num,1);
int ans=1;//记得+1
for(int i=1;i<=tot;i++){
if(e[i].op==1){//左边,加入
int x=lower_bound(b+1,b+1+num,e[i].y1)-b;
update(x,1,1,num,1);
}else if(e[i].op==2){//右边,删除
int x=lower_bound(b+1,b+1+num,e[i].y1)-b;
update(x,-1,1,num,1);
}else if(e[i].op==3){//竖线,查询
int l=lower_bound(b+1,b+1+num,e[i].y1)-b;
int r=lower_bound(b+1,b+1+num,e[i].y2)-b;
ans+=ask(l,r,1,num,1);
}
}
printf("%d\n",ans);
}
return 0;
}