HDU 3642 Get The Treasury (線段樹掃描線進階--求長方體重疊3次或以上的體積)

題意:給定一堆長方體(< =1000),求重疊了大於等於3次的體積。

思路:線段樹掃描線,或者說,掃描面。

這題 |X|,|Y|<=10^6  ,   |Z|<=500

由於Z相對較小,所以,以垂直Z軸的面來掃描整個圖形。

每一個面再用線段樹掃描線,記錄重疊了3次或以上的面積,然後乘以Z軸的變化值,就可以得到重疊了3次或以上的體積。


用到的數據結構分四部分:

一:離散化y值 

用一個Rank數組解決,排序去重複,然後二分求每個值的離散後的值。

二:儲存線段信息

按z 值排序即可,要儲存入邊,出邊等信息。

三:儲存同層中掃描線時的線段信息

需按x值排序。

主要是不同的層用到的線段不一樣,需要很多加入和刪除,寫平衡樹會很麻煩。

所以乾脆直接用IN數組來標記每一個線段是否需要考慮,然後每次都線性掃全部線段。

四:線段樹

線段樹進行區間覆蓋,維護重疊了3次或以上的線段長度。

節點中,C:覆蓋次數 CL[K]:重疊了大於等於K次的線段長度。


代碼如下:

//1170MS 1832K  
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define maxn 2007
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define LL long long
using namespace std;
int n,N;
//一: 離散化y值   
//二:線段信息 :(Z,X,Y1,Y2,出/入邊,出入/層)  排序:(Z,X)
//三:同層線段(層間變化避免重新排序)---節點:(X,Y1,Y2,出/入邊)  排序:(X) 
//四:線段樹 節點:(C,CL[4])

//一: 離散化y值   2*n
int Rank[maxn],Rn;
int InitRank(){//排序去重 
    sort(Rank,Rank+N);Rn=0;
    for(int i=1;i<N;++i){if(Rank[i]!=Rank[i-1]) Rank[++Rn]=Rank[i];}
}
int GetRank(double x){
    int L=0,R=Rn;//[L,R]  first >= x
    while(L^R){
        int M=(L+R)>>1;
        if(Rank[M]<x) L=M+1;
        else R=M;
    }
    return L;
}
//二:線段信息   4*n
int Ln;
struct Lines{
    int z,x,y1,y2,xin,zin,id;
    Lines(){}
    Lines(int z,int x,int y1,int y2,int xin,int zin,int id):z(z),x(x),y1(y1),y2(y2),xin(xin),zin(zin),id(id){}
    bool operator <(const Lines &B)const{return z < B.z;}
}Line[maxn<<1];
//三:同層線段  2*n
struct Node{
    int x,y1,y2,xin,id;
    Node(){}
    Node(int x,int y1,int y2,int xin,int id):x(x),y1(y1),y2(y2),xin(xin),id(id){}
    bool operator < (const Node &B)const{return x < B.x || x==B.x && id<B.id;}
    bool operator ==(const Node &B)const{return x==B.x&&y1==B.y1&&y2==B.y2&&xin==B.xin&&id==B.id;}
}K[maxn];
int Kn;
bool In[maxn];
int GetR(Node X){
    int L=1,R=Kn;//[L,R]  first >= X
    while(L^R){
        int M=(L+R)>>1;
        if(K[M]<X) L=M+1;
        else R=M;
    }
    return L;
}
void Insert(Node X){In[GetR(X)]=1;}
void Delete(Node X){In[GetR(X)]=0;}
//四:線段樹 節點:(C,CL[4])
struct Nodes{
    int C;//Cover
    int CL[4];//CoverLength[0~3]
}ST[maxn<<3];
void PushUp(int rt){
    for(int i=1;i<=3;++i){
        if(ST[rt].C < i) ST[rt].CL[i]=ST[rt<<1].CL[i-ST[rt].C]+ST[rt<<1|1].CL[i-ST[rt].C];
        else ST[rt].CL[i]=ST[rt].CL[0];
    }
}
void Build(int l,int r,int rt){
    if(l==r){
        ST[rt].C=0;
        ST[rt].CL[0]=Rank[l]-Rank[l-1];
        ST[rt].CL[1]=ST[rt].CL[2]=ST[rt].CL[3]=0;
        return;
    }
    int m=(l+r)>>1;
    Build(ls);
    Build(rs);
    ST[rt].C=0;
    ST[rt].CL[0]=ST[rt<<1].CL[0]+ST[rt<<1|1].CL[0];
    PushUp(rt);
} 
void Update(int L,int R,int C,int l,int r,int rt){
    if(L <= l && r <= R){
        ST[rt].C+=C;
        if(l==r){
            ST[rt].CL[1]=ST[rt].C>=1?ST[rt].CL[0]:0;
            ST[rt].CL[2]=ST[rt].C>=2?ST[rt].CL[0]:0;
            ST[rt].CL[3]=ST[rt].C>=3?ST[rt].CL[0]:0;
        }
        else PushUp(rt);
        return;
    }
    int m=(l+r)>>1;
    if(L <= m) Update(L,R,C,ls);
    if(R >  m) Update(L,R,C,rs);
    PushUp(rt);
}
int main(void)
{
    int t;scanf("%d",&t);
    for(int Case=1;Case<=t;++Case){
        scanf("%d",&n);N=Ln=Kn=0;
        for(int i=0;i<n;++i){
            int x1,y1,z1,x2,y2,z2;
            scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);
            //離散化 
            Rank[N++]=y1;
            Rank[N++]=y2;
            //存值部分
            Line[Ln++]=Lines(z1,x1,y1,y2,1,1,i<<1);
            Line[Ln++]=Lines(z1,x2,y1,y2,-1,1,i<<1|1);
            Line[Ln++]=Lines(z2,x1,y1,y2,1,-1,i<<1);
            Line[Ln++]=Lines(z2,x2,y1,y2,-1,-1,i<<1|1); 
            //K
            K[++Kn]=Node(x1,y1,y2,1,i<<1);
            K[++Kn]=Node(x2,y1,y2,-1,i<<1|1);
        }
        InitRank();
        sort(K+1,K+Kn+1);
        sort(Line,Line+Ln);
        memset(In,0,sizeof(In));
        LL Z,PreZ=Line[0].z,PreArea=0,ANS=0;
        int I=0; 
        while(I < Ln){//掃描面 
            Z=Line[I].z;
            ANS+=(Z-PreZ)*PreArea;
            while(I < Ln && Line[I].z==Z){
                //修改掃描邊列表 
                if(~Line[I].zin) Insert(Node(Line[I].x,Line[I].y1,Line[I].y2,Line[I].xin,Line[I].id));
                else Delete(Node(Line[I].x,Line[I].y1,Line[I].y2,Line[I].xin,Line[I].id));
                I++; 
            }
            Build(1,Rn,1);
            int J=1;
            LL X,PreX=K[0].x,PreLen=0,Area=0; 
            while(J <= Kn){//掃描線 
                X=K[J].x;
                Area+=(X-PreX)*PreLen;
                while(J <= Kn && K[J].x==X){
                    //修改線段
                    if(In[J]) Update(GetRank(K[J].y1)+1,GetRank(K[J].y2),K[J].xin,1,Rn,1);
                    J++; 
                }
                PreX=X;
                PreLen=ST[1].CL[3];
            } 
            //更新PreZ,PreArea 
            PreZ=Z;
            PreArea=Area;
        }
        printf("Case %d: %I64d\n",Case,ANS);
    }
return 0;
}



發佈了96 篇原創文章 · 獲贊 375 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章