概述
【题解】
题意:给定平面大小,左下角坐标(0,0),右上角坐标(n,m),给定k条以(xi,yi)为起始点方向为di的射线,询问被切割成多少块。
思路:因为 ,又是射线,所以容易得到最终的块数是所有射线的交点数+1。
因为n和m比较大而点比较少,我们考虑把坐标离散化建立树状数组,用来维护每一条横线的贡献。
整个过程从下往上依次处理查询,所以按y升序排序,且相同的y竖线优先处理。
先把横线和竖线区别处理,用 f 标记是横线还是竖线,
如果是竖线:
如果是向上的竖线,那么从y开始持续有贡献;如果向下,那么从0-y有贡献,所以要再增加一个记录y+1开始没有贡献的点便于后续树状数组的修改操作。
如果是横线:
记录(L,R]表示可到达的部分。
然后轮到竖线就修改树状数组,轮到横线就计算贡献更新答案即可。
代码借鉴于2019杭电暑假多校9:Rikka with Cake【扫描线+树状数组】
【代码】
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=2e5+10;
int n,m,k,cnt,cntx;
struct P{
int f,L,R,id,v; //f区分横竖线
}p[maxn<<1];
int tr[maxn<<1],X[maxn<<1];
bool cmp(P a,P b){return a.id==b.id?a.f<b.f:a.id<b.id;}
int lowbit(int x){return x&(-x);}
int getp(int x){return lower_bound(X+1,X+cntx,x)-X;}
void init()
{
X[cntx++]=n; sort(X+1,X+cntx);
cntx=unique(X+1,X+cntx)-X; //离散化坐标
sort(p,p+cnt,cmp);
for(int i=0;i<=cntx;i++) tr[i]=0;
}
void update(int x,int v){
while(x<=cntx){
tr[x]+=v,x+=lowbit(x);
}
}
LL query(int x)
{
LL res=0;
while(x){
res+=tr[x],x-=lowbit(x);
}
return res;
}
LL solve()
{
init();
LL ans=0;
for(int i=0;i<cnt;++i){
if(!p[i].f) update(getp(p[i].L),p[i].v); //更新树状数组
else ans+=query(getp(p[i].R))-query(getp(p[i].L)); //查询每条横线的贡献,更新答案
}
return ans+1;
}
int main()
{
int T; scanf("%d",&T);
while(T--){
cnt=0,cntx=2;
scanf("%d%d%d",&n,&m,&k);
while(k--){
int x,y; char d;
scanf("%d%d %c",&x,&y,&d);
if(d=='U') p[cnt++]=(P){0,x,y,y,1};
else if(d=='D'){
p[cnt++]=(P){0,x,y,0,1};
p[cnt++]=(P){0,x,y,y+1,-1};
}
else if(d=='L') p[cnt++]=(P){1,0,x,y,0};
else p[cnt++]=(P){1,x-1,n,y,0},X[cntx++]=x-1;
X[cntx++]=x;
}
printf("%lldn",solve());
}
return 0;
}
最后
以上就是炙热哑铃为你收集整理的2019杭电暑期多校第九场 B:Rikka with Cake(离散化+树状数组)的全部内容,希望文章能够帮你解决2019杭电暑期多校第九场 B:Rikka with Cake(离散化+树状数组)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复