离散化 扫描线 学习

离散化

扫描线

心态崩了, 为什么oj上认 4*n长度的线段树 不认2*n长度的, 就是不知道为啥不能过,

超时代码, 等心态好了来改

#include<cstdio>
#include<algorithm>
#define max 1010
using namespace std;
struct node {
    double xl,xr,y;
    int  flag;
};
struct node1{
    int left,right,tag;
    double high,yl;
};
node1 tree[2*max];
bool cmp(node a,node b){
    return a.y<b.y;
}
int n;
int x_len=1;
node line[2*max];
double dis_x[2*max];
void build(int l,int r,int index){
    tree[index].left=l;
    tree[index].right=r;
    tree[index].tag=0;
    tree[index].high=0;
    tree[index].yl=0;
    if(l+1==r){
        return ;
    }
    int mid =(l+r)>>1;
    build(l,mid,index+1);
    build(mid,r,index+(mid-l)*2);
} 
int get_index(double a,int len){  //这里是将离散的坐标找到原来的位置,用二分法 ,len值得是dis_x数组长度,其实是2n 
    //将一个有序数组存在 dis_x中 ,现在知道其中一个,求其下标 
    int l=0,r=len;
    while(l<r){
        int mid=(l+r)>>1;
        if(dis_x[mid]>a)
            r=mid-1;
        else if (dis_x[mid]<a)
            l=mid+1;
        else 
            return mid;
    }
}
void update(int ll,int rr,int index,node line){
    if(tree[index].left==tree[index].right-1){
        /
        if(tree[index].tag==1&&line.flag==1)   tree[index].yl=line.y;
        else if(tree[index].tag==2&&line.flag==-1){
            tree[index].high+=line.y-tree[index].yl;
            tree[index].yl=0.0;
        }
        tree[index].tag+=line.flag;
        return ;
    }
    int left=tree[index].left;
    int right=tree[index].right;
    int mid=(left+right)>>1;
    if(rr<=mid){
        update(ll,rr,index+1,line);
    }
    else if(ll>=mid){
        update(ll,rr,index+(mid-left)*2,line);
    }
    else {
        update(ll,mid,index+1,line);
        update(mid,rr,index+(mid-left)*2,line);
    }
}
double query(int index){
    if(tree[index].left==tree[index].right-1){
        return (dis_x[tree[index].right]-dis_x[tree[index].left])*tree[index].high;
    }
    return query(index+1)+
    query(index+((tree[index].right+tree[index].left)/2-tree[index].left)*2);
}
void lisan(){
    x_len=1;
    sort(line +1,line+2*n+1,cmp);
    sort(dis_x+1,dis_x+2*n+1);
    dis_x[0]=-1; 
    for(int i = 1; i <=2*n; i++) {    
        if(dis_x[i] == dis_x[i-1])
            continue;
           dis_x[x_len++] = dis_x[i]; 
    }
}
void mysacanf(){
    double x1,x2,y1,y2;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
        line[2*i-1].xl=x1;
        line[2*i-1].xr=x2;
        line[2*i-1].y=y1;
        line[2*i-1].flag=1;
        dis_x[2*i-1]= x1;
        line[2*i].xl=x1;
        line[2*i].xr=x2;
        line[2*i].y=y2;
        line[2*i].flag=-1;
        dis_x[2*i]=x2;
    }
}
void insert(){
    for(int i=1;i<2*n;i++){
        int xl=get_index(line[i].xl,x_len);
        int xr=get_index(line[i].xr,x_len);
        update(xl,xr,1,line[i]);
    }
}
int main(){
    int num;
    scanf("%d",&num);
    while(num--){
        mysacanf();
         lisan();
        build(1,x_len,1);
        insert();
        printf("%.2lf \n",query(1));
    }
    return 0;
} 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值