2019HDU多校九1002 (线段树求线段交点个数)

本文介绍了一种使用线段树算法解决由平行于坐标轴的射线将矩形区域分割成多个封闭部分的问题。通过离散化坐标和线段树维护,实现对射线的高效处理,详细解析了算法的实现步骤和代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

hdu6681

题意:
给你 k k k 条平行于x轴或y轴的射线, 问这些射线把封闭区域 n ∗ m n*m nm的矩形分成了几个封闭部分。

思路:
因为射线都是平行于坐标轴的,那么考虑线段树维护。

离散化坐标后,按照 x x x坐标从小到大排序。
第一遍:如果当前点是竖着分割,那么分割的区间值加一,表示当前这段区间 y y y坐标都有射线经过。 如果当前点是横着分割的,那么直接单点查询当前点 y y y坐标的值。

(debug半天,发现pushdown写错了sdajlskfdjas)

#include <bits/stdc++.h>

using namespace std;
const int maxn = 1e5+5;
typedef long long ll;
struct node{
    int x,y;
    char dir[2];
}p[maxn<<2];
bool cmp(node a,node b){
    return a.x < b.x;
}
vector<int>idx,idy;
ll sum[maxn<<2],add[maxn<<2];
void pushup(int rt){
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}

void pushdown(int rt,int len){
    if(add[rt]){
        add[rt<<1] += add[rt];
        add[rt<<1|1] += add[rt];
        sum[rt<<1] += 1LL*add[rt]*(len-(len>>1));
        sum[rt<<1|1] += 1LL*add[rt]*((len>>1));
        add[rt] = 0;        
    }
}
void build(int l,int r,int rt){
    sum[rt] = add[rt] = 0;
    if(l == r){
        return ;
    }
    int mid = l+r>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    
}

void update(int l,int r,int rt,int L,int R,ll val){
    if(L <= l && R >= r){
        sum[rt] += 1LL*(r-l+1)*val;
        add[rt] += val;
        return;
    }
    pushdown(rt,r-l+1);
    int mid = (l+r)>>1;
    if(L <= mid) update(l,mid,rt<<1,L,R,val);
    if(R > mid) update(mid+1,r,rt<<1|1,L,R,val);
    pushup(rt);
}

ll query(int l,int r,int rt, int pos){
    if(l == r){
        return sum[rt];
    }
    pushdown(rt,r-l+1);
    int mid = (l+r)>>1;
    if(pos <= mid) return query(l,mid,rt<<1,pos);
    else return query(mid+1,r,rt<<1|1,pos);
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        idx.clear(), idy.clear();
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
        for(int i = 1; i <= k; i++){
            scanf("%d%d%s",&p[i].x,&p[i].y,p[i].dir);
            idx.push_back(p[i].x);
            idy.push_back(p[i].y);
            
        }
        sort(idx.begin(), idx.end());
        idx.erase(unique(idx.begin(), idx.end()), idx.end());

        sort(idy.begin(), idy.end());
        idy.erase(unique(idy.begin(), idy.end()), idy.end());

        for(int i = 1; i <= k; i++){
            p[i].x = lower_bound(idx.begin(), idx.end(), p[i].x) - idx.begin() + 1;
            p[i].y = lower_bound(idy.begin(), idy.end(), p[i].y) - idy.begin() + 1;
        }

        sort(p+1,p+k+1,cmp);
        ll ans = 0;
        build(1,100001,1);
        
        for(int i = 1; i <= k; i++){
            if(p[i].dir[0] == 'U') update(1,100001,1,p[i].y,100000,1ll);
            if(p[i].dir[0] == 'D') update(1,100001,1,1,p[i].y,1ll);
            if(p[i].dir[0] == 'L') ans += query(1,100001,1,p[i].y);
            //printf("sum[1],%lld\n",sum[1]);
            //if(p[i].dir[0] == 'R') ans += query(1,100000,1,p[i].y);
        }

        build(1,100001,1);
        
        for(int i = k; i >= 1; i--){
            if(p[i].dir[0] == 'U') update(1,100001,1,p[i].y,100000,1ll);
            if(p[i].dir[0] == 'D') update(1,100001,1,1,p[i].y,1ll);
            if(p[i].dir[0] == 'R') ans += query(1,100001,1,p[i].y);
            //if(p[i].dir[0] == 'R') ans += query(1,100000,1,p[i].y);
        }
        printf("%lld\n",ans+1);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值