hdu1255 ( 线段树扫描求面积并 )

矩形面积交。线段树的好题,第三次做了~~~

 注意:如果题目是连续型线段,二分线段判断条件是l+1==r 那么这里不能是mid+1,因为这里是连续型的mid和mid+1之间也是线段    其他题目中点是离散的123... 左边就是[1,mid],右边是[mid+1,r],中间划分线就是mid和mid+1中间这块(这时这块是没用的~)

 

ac代码:

#include<bits/stdc++.h>
#define per(i,a,b) for(int i=a;i<=b;i++)
#define mod 1000000007
using namespace std;
typedef long long ll;
//#define int long long
const int inf =0x3f3f3f3f;
const double eps=1e-8;
int read(){
    char ch=getchar();
    int res=0,f=0;
    while(ch<'0' || ch>'9'){f=(ch=='-'?-1:1);ch=getchar();}
    while(ch>='0'&&ch<='9'){res=res*10+(ch-'0');ch=getchar();}
    return res*f;
}
// ------------------------head
const int siz=1005;
int T,n;
struct Line{
    int l,r,v;
    double x1,x2,y;
}line[siz*2];
bool cmp(Line a,Line b){return a.y<b.y;}
double point[siz*2];
vector<double>vp;
int Enum=0,pnum=0;;
void init(){
    Enum=0;
    pnum=0;
}
struct Node{ //面积并 也就是求>=两条边一起扫过的面积
    int l,r,v;//v:重叠次数
    double lf,rf;//先记录原来的lf,rf,才能后来对应到离散化的l,r
    double one,two;//覆盖>=一次/>=两次的长度
}tr[siz*2*4];
void build(int u,int l,int r){
    tr[u].l=l;tr[u].r=r;
    tr[u].lf=point[l];tr[u].rf=point[r];
    tr[u].v=0;
    tr[u].one=tr[u].two=0;
    if(l==r-1)return;
    int mid=(l+r)>>1;
    build(u*2,l,mid);
    build(u*2+1,mid,r);
}
void cal(int u){//要考虑到叶子节点和非叶子节点
    if(tr[u].v>=2){tr[u].one=tr[u].two=tr[u].rf-tr[u].lf;}
    else if(tr[u].v==1){
        tr[u].one=tr[u].rf-tr[u].lf;
        if(tr[u].l+1==tr[u].r){tr[u].two=0;}
        else{tr[u].two=tr[u<<1].one+tr[(u<<1)|1].one;}
    }
    else{
        if(tr[u].l+1==tr[u].r){tr[u].one=tr[u].two=0;}
        else {
            tr[u].one=tr[u<<1].one+tr[(u<<1)|1].one;
            tr[u].two=tr[u<<1].two+tr[u*2+1].two;
        }
    }
}
void update(int u,int e){//e means the num of line
    if(line[e].l<=tr[u].l&&line[e].r>=tr[u].r){
        tr[u].v+=line[e].v;
        cal(u);
        return;
    }
    int mid=(tr[u].l+tr[u].r>>1);
    if(line[e].l<mid)update(u<<1,e);
    if(line[e].r>mid)update((u<<1)|1,e);
    cal(u);
}


signed main()
{
    freopen("Data_In.txt","r",stdin);
    scanf("%d",&T);
    double x1,y1,x2,y2;
    while(T--){
        scanf("%d",&n);
        init();
        per(i,1,n){
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            point[pnum++]=x1;point[pnum++]=x2;
            line[Enum].x1=x1;line[Enum].x2=x2;
            line[Enum].v=1;line[Enum++].y=y1;
            line[Enum].x1=x1;line[Enum].x2=x2;
            line[Enum].v=-1;line[Enum++].y=y2;
        }
        sort(line,line+Enum,cmp);
        sort(point,point+pnum);
        pnum=unique(point,point+pnum)-point;
        per(i,0,Enum-1){//这里离散化重新记录中注意编号
            //从0开始编号还是从1开始编号都不用再减1,,,很妙啊!!!
            line[i].l=lower_bound(point,point+pnum,line[i].x1)-point;
            line[i].r=lower_bound(point,point+pnum,line[i].x2)-point;
        }
        build(1,0,pnum-1);
        update(1,0);
        double ans=0;
        per(i,1,Enum-1){
            ans+=(tr[1].two*(line[i].y-line[i-1].y));
            update(1,i);
        }
        printf("%.2lf\n",ans);
    }

    return 0;
}

 

posted @ 2018-07-18 16:36  WindFreedom  阅读(161)  评论(0)    收藏  举报