hdu1542 矩阵面积并+线段树+离散化+二分+扫描线

这道题还是反应出我的很多问题
一开始我的没有接触过扫描线这东西 于是找博客学习了 先对着1542的cpp使劲看
觉得自己看的差不多了 就开始自己写 (我觉得编程你觉得自己看懂了没用 还是自己理解了写出来懂的比较透彻)
也发现了自己很多问题 比如freopen这个东西 虽然调试的时候比较方便 但是很多时候交题的时候忘了注释掉,这还是比较尴尬的。所以我觉得自己还是不能有这个坏习惯,还是不要偷懒,每次写freopen都加上条件编译

这道题就是一根扫描线往一个方向扫 想了解扫描线大家可以自行百度 大牛都讲的很清楚 我就不啰嗦
这里有一个 我开始也很不理解的地方 就是r+1 r-1这个问题
我来解释一下 可能比别人解释的清楚一点

先看代码

#include<iostream>
using namespace std;
#include<cstdio>
#include<algorithm>
#include<cstring>

const int maxn=1005;
int n;
struct note{
    double x1,x2,y;
    int cover;
    bool operator <(const note&aa)const{
        return y<aa.y;
    }
}in[maxn];
double b[maxn];
struct notes{
    int l,r;
    int cover;
    double sum;
}a[maxn];
void init(int i,int l,int r){
    a[i].l=l;
    a[i].r=r;
    a[i].cover=0;
    a[i].sum=0;
    if(l==r)return;
    int mid=l+r>>1;
    init(i<<1,l,mid);
    init(i<<1 |1,mid+1,r);
}
int m;
int finds(double x){
    int l=0,r=m-1;
    while(l<=r){
        int mid=l+((r-l)>>1);
        if(b[mid]==x)return mid;
        else if(b[mid]<x)l=mid+1;
        else r=mid-1;
    }
}
void dp(int i){
    if(a[i].cover)a[i].sum=b[a[i].r+1]-b[a[i].l];
    else if(a[i].l==a[i].r)a[i].sum=0;
    else a[i].sum=a[i<<1].sum+a[i<<1 |1].sum;
}
void updata(int start,int aim,int cover,int i){
    if(a[i].l==start&&a[i].r==aim){
        a[i].cover+=cover;
        dp(i);
        return;
    }
    int mid=a[i].l+((a[i].r-a[i].l)>>1);
    if(start>mid)updata(start,aim,cover,i<<1 |1);
    else if(aim<=mid)updata(start,aim,cover,i<<1);
    else{
        updata(start,mid,cover,i<<1);
        updata(mid+1,aim,cover,i<<1 |1);
    }
    dp(i);
}
int main(){
    int coun_=0;
    #ifdef ONLINE_JUDGE
    #else
    freopen("1542.txt","r",stdin);
    #endif // ONLINE_JUDGE 

    while(cin>>n,n){
        int coun=0;
        for(int i=0;i<n;i++){
            double x1,x2,x3,x4;
            cin>>x1>>x2>>x3>>x4;
            in[coun].x1=x1;
            in[coun].x2=x3;
            in[coun].y=x2;
            in[coun].cover=1;
            b[coun]=x1;
            coun++;
            in[coun].x1=x1;
            in[coun].x2=x3;
            in[coun].y=x4;
            in[coun].cover=-1;
            b[coun]=x3;
            coun++;
        }
        sort(b,b+coun);
        sort(in,in+coun);
        m=1;
        for(int i=1;i<coun;i++){
            if(b[i]!=b[i-1]){
                b[m++]=b[i];
            }
        }
        init(1,0,m-1);
        double ans=0;
        for(int i=0;i<coun-1;i++){
            int l=finds(in[i].x1);
            int r=finds(in[i].x2)-1;
            updata(l,r,in[i].cover,1);
            ans+=a[1].sum*(in[i+1].y-in[i].y);
        }
        printf("Test case #%d\nTotal explored area: %.2lf\n\n",++coun_,ans);
    }
    return 0;
}

hdu1542 矩阵面积并+线段树+离散化+二分+扫描线_第1张图片

这是线段树建树之后 大家可以发现如果我们想要寻找0-2这个区间 这颗线段树就会找到0-1和2-2这两个区间,然后我们看统计的这个函数

void dp(int i){
    if(a[i].cover)a[i].sum=b[a[i].r+1]-b[a[i].l];
    else if(a[i].l==a[i].r)a[i].sum=0;
    else a[i].sum=a[i<<1].sum+a[i<<1 |1].sum;
}

当左边和右边相等时 ,sum为0,换言之,我们找到的0-2的区间的sum值实际上是0-1这个区间的,这明显不是我们想要的,怎么改变?我们在updata之前就-1,然后到计算的时候我们再+1,这样,图上0-0这个区间代表0-1,1-1这个区间代表1-2,2-2这个区间代表2-3,有了这三个,0-3里面任何区间都是这三个区间组成的,就不会出现边界没有计算的情况了!
请大家仔细想一下!

你可能感兴趣的:(hdu1542 矩阵面积并+线段树+离散化+二分+扫描线)