更多多校信息←请点击这里
Problem Description
传送门
Rikka’s birthday is on June 12th. The story of this problem happens on that day.
Today is Rikka’s birthday. Yuta prepares a big cake for her: the shape of this cake is a rectangular of n centimeters times m centimeters. With the guidance of a grimoire, Rikka is going to cut the cake.
For simplicity, Rikka firstly builds a Cartesian coordinate system on the cake: the coordinate of the left bottom corner is (0,0) while that of the right top corner is (n,m). There are K instructions on the grimoire: The ith cut is a ray starting from (xi,yi) while the direction is Di. There are four possible directions: L, passes (xi−1,yi); R, passes (xi+1,yi); U, passes (xi,yi+1); D, passes (xi,yi−1).
Take advantage of the infinite power of Tyrant’s Eye, Rikka finishes all the instructions quickly. Now she wants to count the number of pieces of the cake. However, since a huge number of cuts have been done, the number of pieces can be very large. Therefore, Rikka wants you to finish this task.
Input
The first line of the input contains a single integer T(1≤T≤100), the number of the test cases.
For each test case, the first line contains three positive integers n,m,K
(
1
≤
n
,
m
≤
1
0
9
,
1
≤
K
≤
1
0
5
)
(1≤n,m≤10^9,1≤K≤10^5)
(1≤n,m≤109,1≤K≤105), which represents the shape of the cake and the number of instructions on the grimoire.
Then K lines follow, the ith line contains two integers xi,yi
(
1
≤
x
i
<
n
,
1
≤
y
i
<
m
)
(1≤xi<n,1≤yi<m)
(1≤xi<n,1≤yi<m)and a char Di∈{‘L’,‘R’,‘U’,‘D’}, which describes the ith cut.
The input guarantees that there are no more than 5 test cases with K>1000, and no two cuts share the same x coordinate or y coordinate, i.e.,
∀
1
≤
i
<
j
≤
K
∀1≤i<j≤K
∀1≤i<j≤K, xi≠xj and yi≠yj.
Output
For each test case, output a single line with a single integer, the number of pieces of the cake.
Hint
The left image and the right image show the results of the first and the second test case in the sample input respectively. Clearly, the answer to the first test case is 3 while the second one is 5.
Sample Input
2
4 4 3
1 1 U
2 2 L
3 3 L
5 5 4
1 2 R
3 1 U
4 3 L
2 4 D
Sample Output
3
5
题目大意:
在一个n*m的矩形内,有k个点,每个点都有一个方向(U,R,D,L)代表从这个点开始根据这个方向切割这个矩形。问最后这个矩形被切割成多少部分?
题目思路:
听说权值线段树和树状数组也可以ac。
这里是最简单的区间加法的普通线段树。
通过观察题目很容易发现就是求射线交点的个数。
由于x,y很大,但是n不大,所以一定有离散化操作。
这里我们离散化y轴。
我们先求L和U,D的交点
然后按x的坐标从小到大,依次将U和D的点加入线段树。每加入一个点x,1-x的区间+1.当遇到L,查询L点离散化后的y坐标(单点查询)即可。
也就是:
假设
tree 0 0 0 0 0 0
(D)x=2时,有y=3
tree 1 1 1 0 0 0
(U)x=3时,有y=3
tree 1 1 2 1 1 1
(L)x=4时,有y=3
ans+=2;
(L)x=5时,有y=4
ans+=1;
因为xi≠xj and yi≠yj.所以直接按x排序插入线段树即可。晚插入的L的x一定长于先插入的。
同理可得L和U,D的交点。(按x从大到小)
AC_code:
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int N=2e5+1000;
ll tree[N<<2],lzadd[N<<2];
void init(){
memset(tree,0,sizeof(tree));
memset(lzadd,0,sizeof(lzadd));
}
void PushDown(int root,int ln,int rn){
if(lzadd[root]){
lzadd[root<<1]+=lzadd[root];
lzadd[root<<1|1]+=lzadd[root];
tree[root<<1]+=lzadd[root]*ln;
tree[root<<1|1]+=lzadd[root]*rn;
lzadd[root]=0;
}
}
void Update(int l,int r,int L,int R,int root) { //D:Update(1,id,1,k,1); (1~id)+1
int m=(L+R)>>1; //U:Update(id,k,1,k,1); (id~k)+1
PushDown(root,m-L+1,R-m);
if(l<=L&&R<=r) {
tree[root]+=(R-L+1);
lzadd[root]+=1;
return;
}
if(l<=m)
Update(l,r,L,m,root<<1);
if(r>m)
Update(l,r,m+1,R,root<<1|1);
tree[root]=tree[root<<1]+tree[root<<1|1];
}
ll query(int x,int l,int r,int root){ //query(id,1,k,1); 单点查询
int m=(r+l)>>1;
PushDown(root,m-l+1,r-m);
if(l==r){
return tree[root];
}
if(x<=m)
return query(x,l,m,root<<1);
else
return query(x,m+1,r,root<<1|1);
}
int t,n,m,k;
struct node { //点的信息
int x,y;
char c;
bool operator<(const node &a)const {
return x<a.x;
}
}no[N];
vector<int>v;
int getid(int x){
return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
int main() {
scanf("%d", &t);
while(t--) {
scanf("%d%d%d",&n,&m,&k);
init(),v.clear();
for(int i=1;i<=k;i++) {
scanf("%d%d %c",&no[i].x,&no[i].y,&no[i].c);
v.push_back(no[i].y); //存y点的坐标
}
sort(no+1,no+k+1); //总坐标先对x排序,
sort(v.begin(), v.end()); //对y坐标排序(离散化操作)
ll ans=1;
//算向右的与上下的交点
//因为xi≠xj and yi≠yj,所以不会有点在同一直线上。否则排序需要先U和D在L和R
for(int i=1;i<=k;i++) { //按x从小到大
int id=getid(no[i].y); //离散化
if(no[i].c=='U')
Update(id,k,1,k,1); //(id~k)+1
else if(no[i].c=='D')
Update(1,id,1,k,1); //(1~id)+1
else if(no[i].c=='L')
ans+=query(id,1,k,1); //查询id点的值
}
init(); //初始化
//算向左的与上下的交点
for(int i=k;i>0;i--){ //按x从大到小
int id=getid(no[i].y);
if(no[i].c=='U')
Update(id,k,1,k,1);
else if(no[i].c=='D')
Update(1,id,1,k,1);
else if(no[i].c=='R')
ans+=query(id,1,k,1);
}
printf("%lld\n", ans);
}
return 0;
}