1. 程式人生 > >poj 1151 hdu 1542 Atlantis 線段樹掃描線,詳細講解,(*^__^*) 嘻嘻……

poj 1151 hdu 1542 Atlantis 線段樹掃描線,詳細講解,(*^__^*) 嘻嘻……

我的掃面線第一題,一開始看網上講的都好抽象,最後還是研究別人程式碼整明白的,所以我要寫一個直觀的,哈哈哈!!希望大家都能看懂

如圖虛線將整個圖型分成三個矩形,我們現將每個點的x進行排序,也就是(10,15,20,25.5)

這樣就知道矩形的長了,還差寬,然後我們就要開始掃描線啦

先每個點的y值離散話,因為我們要求的是對映在x軸的線段,然後建樹,共有t哥點,樣立t-1等於4

下面的線段樹我每個離散花後的點對應的y值我都標記上了

將一號邊加入線段,先加入一號邊,二號邊三號邊四號邊具體過程建議自己模擬一下

我每個線段樹的點用s標記這條邊被覆蓋還是沒被都蓋,每條邊的flag表示這天邊是入度還是出度

注意啊!!我這個圖x,y軸畫反啦


#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define N 300
struct Node{
    double x;double y1;double y2;
    int flag;
}node[N];
bool cmp(Node a,Node b){
    return a.x-b.x<0.0000001;
}
double y[N];
struct node{
    int l;int r;double ml;double mr;int s;double len;
}a[N*3];
void build(int i,int left,int right){
    a[i].l=left;
    a[i].r=right;
    a[i].ml=y[left];
    a[i].mr=y[right];
    a[i].s=0;
    a[i].len=0;
    if(a[i].l+1==a[i].r){
        return ;
    }
    int mid=(left+right)>>1;
    build(i*2,left,mid);
    build(i*2+1,mid,right);//建樹時注意這裡不是mid+1,因為做相減的時候如果mid+1這麼建回到值左孩子的右邊與有孩子的左邊無法進行運算
}
void callen(int i){

    if(a[i].s>0){//注意這裡不是所有邊都是左孩子的長度加上右孩子的長度,他存在一個覆蓋問題
        a[i].len=a[i].mr-a[i].ml;
    }else if(a[i].r-a[i].l==1){
        a[i].len=0;
    }else{
        a[i].len=a[i*2].len+a[i*2+1].len;
    }
    return ;
}
void updata(int i,Node b){
    if(a[i].ml==b.y1&&a[i].mr==b.y2){
        a[i].s+=b.flag;
        callen(i);
        return ;
    }
    if(b.y2<=a[i*2].mr) updata(i*2,b);
    else if(b.y1>=a[i*2+1].ml) updata(i*2+1,b);
    else{
        Node temp=b;
        temp.y2=a[i*2].mr;
        updata(i*2,temp);
        temp=b;
        temp.y1=a[i*2+1].ml;
        updata(i*2+1,temp);
    }
    callen(i);
    return ;
}
int main(){
//    freopen("in.txt","r",stdin);
    int n,t,p=1,te;
    double x1,x2,y1,y2;
    while(scanf("%d",&n),n){
            t=1;
            for(int i=0;i<n;i++){
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            node[t].x=x1;
            node[t].y1=y1;
            node[t].y2=y2;
            node[t].flag=1;//入邊
            y[t++]=y1;
            node[t].x=x2;
            node[t].y1=y1;
            node[t].y2=y2;
            node[t].flag=-1;//出邊
            y[t++]=y2;
        }
        sort(node+1,node+t,cmp);
        sort(y+1,y+t);
        build(1,1,t-1);
        updata(1,node[1]);
        double sum=0;
        for(int i=2;i<t;i++){
            sum+=a[1].len*(node[i].x-node[i-1].x);
            updata(1,node[i]);
        }
        printf("Test case #%d\n",p++);
        printf("Total explored area: %.2lf\n\n",sum);
    }
    return 0;
}