2019杭电暑期多校第九场 B:Rikka with Cake(离散化+树状数组)

【题解】

题意:给定平面大小,左下角坐标(0,0),右上角坐标(n,m),给定k条以(xi,yi)为起始点方向为di的射线,询问被切割成多少块。

思路:因为 0<xi<n,0<yi<m,又是射线,所以容易得到最终的块数是所有射线的交点数+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("%lld\n",solve());
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值