hdu 6681 2019 杭电多校九1002 Rikka with Cake(扫描线+树状数组)

1 篇文章 0 订阅
1 篇文章 0 订阅

题意:给一个矩形,在矩形内部有很多射线,这些射线的起点不会碰到矩形边界,问这些射线把矩形分成了几部分
题解:分成的区域数等于线段交点数加一,推导还是看jls的题解把
单说求交点个数的问题,我的方法就是扫描线+线段树/树状数组,但是树状数组不太了解,那就用树状数组做吧!
1e9的数据肯定先离散化
我把横线(平行于x轴的)当做枚举的对象,那些竖线(平行于y轴的)就记录他们的头尾,然后头设置值为1,尾设置值为-1,把横线记录左边的x右边的x和高度y,然后按y排序,扫描线扫到第一条横线的时候,把所有高度小于等于这条横线的竖线的起始点和结尾点都用树状数组单点更新,更新完毕就用树状数组查询横线包含的区间内所有值的和,就是这条线的交点个数
注意一下不是记录竖线结尾点设置为-1,而是记录比竖线结尾y值大1的点为-1,为了表示射线无线延长的特点,我在离散的时候还加入了0作为最小值,和max(m,n)作为最大值

#include <iostream>
#include <stdio.h>
#include <queue>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <math.h>
#include <time.h>
#include <algorithm>
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
const ll mod=998244353;
const int maxn=1e6+100;

int n,m,k;
int sum[maxn];

struct Line
{
    int xl,xr,y;
    Line(){}
    Line(int xl,int xr,int y):xl(xl),xr(xr),y(y){}
};

struct PO
{
    int x,y,f;
    PO(){}
    PO(int x,int y,int f):x(x),y(y),f(f){}
};

struct nn
{
    int x,y;
    char a[2];
}o[maxn];

vector<Line>H;
vector<PO>S;
vector<int>ls;

int cmpPO(PO a,PO b)
{
    return a.y<b.y;
}

int cmpL(Line a,Line b)
{
    return a.y<b.y;
}

void update(int i,int tot,int c)
{
    for(;i<tot;i+=i&(-i))sum[i]+=c;
}

int query(int i)
{
    int res=0;
    for(;i>0;i-=i&(-i))res+=sum[i];
    return res;
}

int main() {
//    freopen("in1.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    int t;
    scanf("%d",&t);
    while(t--){
        H.clear();
        S.clear();
        ls.clear();
        memset(sum,0,sizeof sum);
        scanf("%d%d%d",&n,&m,&k);
        ls.push_back(max(n,m));
        ls.push_back(0);
        for(int i=1;i<=k;i++){
            scanf("%d%d%s",&o[i].x,&o[i].y,o[i].a);
            ls.push_back(o[i].x);
            ls.push_back(o[i].y);
        }
        sort(ls.begin(),ls.end());
        int tot=unique(ls.begin(),ls.end())-ls.begin();
        for(int i=1;i<=k;i++){
            int x=lower_bound(ls.begin(),ls.begin()+tot,o[i].x)-ls.begin();
            int y=lower_bound(ls.begin(),ls.begin()+tot,o[i].y)-ls.begin();
            if(o[i].a[0]=='U'){
                S.push_back(PO(x,y,1));
                S.push_back(PO(x,tot-1,-1));
            }
            else if(o[i].a[0]=='D'){
                S.push_back(PO(x,1,1));
                S.push_back(PO(x,y+1,-1));
            }
            else if(o[i].a[0]=='L'){
                H.push_back(Line(1,x,y));
            }
            else if(o[i].a[0]=='R'){
                H.push_back(Line(x,tot-1,y));
            }
        }
        sort(H.begin(),H.end(),cmpL);
        sort(S.begin(),S.end(),cmpPO);
        int ans=1,posP=0;
        for(int i=0;i<H.size();i++){
            while(posP<S.size() && S[posP].y<=H[i].y){
                update(S[posP].x,tot,S[posP].f);
                posP++;
            }
            ans+=query(H[i].xr)-query(H[i].xl-1);
        }
        printf("%d\n",ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值