HDOJ-6681(离散化+线段树)

Rikka With Cake

HDOJ-6681

  1. 最终的答案为射线的交点数加一。当然,我们也可以证明。证明需要用到欧拉公式 V−E+F=2 V-E+F=2V−E+F=2 。设射线的交点共 c cc 个。则在这个图中,V=K+4+K+c=2K+c+4 V=K+4+K+c=2K+c+4V=K+4+K+c=2K+c+4 , E=2∑(ci+1)+K+4=2K+2c+4 E=2\sum (c_i+1)+K+4=2K+2c+4E=2∑(ci+1)+K+4=2K+2c+4 。因此 F=2−V+E=c+2 F=2-V+E=c+2F=2−V+E=c+2 。减去外面的无穷区域,得出答案为 c+1 c+1c+1 。
    原文链接:https://blog.csdn.net/qq_43549984/article/details/99762559
  2. 首先需要先按y的值进行从小到大排序。
  3. 再对y进行离散化,所谓离散化就是将y排序后的点放在一个数组中,用点在数组中的序号代替y,达到缩小范围的作用。
  4. 其次再根据x从小到大排序,因为要根据x开始遍历。首先从左到右遍历方向指向左的点,计算交点。如果是上下方向的则update线段树记录每个点的y覆盖的线段的长度。再从右到左遍历。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
using namespace std;
int n,m,k;
struct Line{
    int x;
    int y;
    char dir;
    Line(int x1,int y1,char dir1):x(x1),y(y1),dir(dir1){}
    Line(){}
};
Line line[100005];
long long sumy[100005<<2];//记录每一个纵坐标上有多少条上下方向的线经过
long long lazy[100005<<2];//懒标记
bool cmp1(Line a,Line b){
    return a.x<b.x;
}
bool cmp2(Line a,Line b){
    return a.y<b.y;
}
void build(int cnt,int l,int r){
    sumy[cnt]=0;
    lazy[cnt]=0;
    if(l!=r){
        int mid=(l+r)>>1;
        build(cnt<<1,l,mid);
        build(cnt<<1|1,mid+1,r);
    }
}
void update(int x,int y,int cnt,int l,int r){
    if(x<=l&&y>=r){
        lazy[cnt]++;
        sumy[cnt]+=(r-l+1);
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid)
        update(x,y,cnt<<1,l,mid);
    if(y>mid)
        update(x,y,cnt<<1|1,mid+1,r);
}
void push_down(int cnt,int l,int r){
    int lc=cnt<<1;
    int rc=cnt<<1|1;
    int mid=(l+r)>>1;
    lazy[lc]+=lazy[cnt];
    sumy[lc]+=1LL*(mid-l+1)*lazy[cnt];//long long 和 int相乘 ?
    lazy[rc]+=lazy[cnt];
    sumy[rc]+=1ll*(r-mid)*lazy[cnt];
    lazy[cnt]=0;
}
long long query(int q,int cnt,int l,int r){
    if(l==r&&l==q){
        return sumy[cnt];
    }
    push_down(cnt,l,r);
    int mid=(l+r)>>1;
    if(l<=q&&r>=q){
        if(q<=mid){
            return query(q,cnt<<1,l,mid);
        }else{
            return query(q,cnt<<1|1,mid+1,r);
        }
    }else return 0;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--){
        cin>>n>>m>>k;
        for(int i=0;i<k;i++){
            cin>>line[i].x>>line[i].y>>line[i].dir;
            //cout<<line[i].x<<line[i].y<<line[i].dir<<endl;
        }
        sort(line,line+k,cmp2);
        for(int i=0;i<k;i++){
            line[i].y=i+1;
        }
        sort(line,line+k,cmp1);
        long long ans=0;
        build(1,1,k);
        for(int i=0;i<k;i++){//-------------------------left to right
            if(line[i].dir=='U')
                update(line[i].y,k,1,1,k);
            else if(line[i].dir=='D')
                update(1,line[i].y,1,1,k);
            else if(line[i].dir=='L'){
                ans+=query(line[i].y,1,1,k);
            }
        }
        build(1,1,k);
        for(int i=k-1;i>=0;i--){//-------------------------right to left
            if(line[i].dir=='U')
                update(line[i].y,k,1,1,k);
            else if(line[i].dir=='D')
                update(1,line[i].y,1,1,k);
            else if(line[i].dir=='R'){
                ans+=query(line[i].y,1,1,k);
            }
        }
        cout<<ans+1<<endl;
    }
    return 0;
}

转载于:https://www.cnblogs.com/GarrettWale/p/11396676.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值