HDU - 1542 Atlantis

一道非常经典的线段树简单题(by_YK)

线段树求矩形面积并

一开始觉得非常简单(自己太高看自己了),就直接去做了周长的,然后YY了大半晚上WA成SB,最后去抄了题解,似乎有一种跑两遍的算法,但感觉十分不优美就没有去学,网上的代码大多有100~180不等,幸运地找到了一个写得非常优美的70+代码。

然后写面积就比较简单了

沿着排序后的x扫,另一维建线段树,每次插入一段新的区间后,答案就增加(X[I+1]-X[I])*SUM[1]

很坑爹的是这题不输出两个换行符就会PE?

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
const int maxn=5000+5;
using namespace std;
int n,tot,sz;
double a,b,c,d,y[maxn],ql,sum[maxn],qr,sg[maxn],ans,val;
struct edge {
    double x,y1,y2,v;
    edge(){}
    edge(double x,double y1,double y2,double v):x(x),y1(y1),y2(y2),v(v){}
    friend bool operator <(const edge &a,const edge&b) {
        return a.x<b.x||(a.x==b.x&&a.v>b.v);
    }
} e[maxn];
void clear() {
    ans=tot=sz=0;
    for(int i=0;i<=500;i++) sg[i]=sum[i]=y[i]=0;
}
#define mid ((l+r)>>1)
#define lc x<<1
#define rc x<<1|1
void add(int x,int l,int r) {
    if(y[l]>=ql&&y[r]<=qr) sg[x]+=val;
    else {
        if(ql<y[mid]) add(lc,l,mid);
        if(qr>y[mid]) add(rc,mid,r);
    }
    if(sg[x]) {sum[x]=y[r]-y[l];}
    else if(l==r) sum[x]=0;
    else sum[x]=sum[lc]+sum[rc];
    
}
int main()
{
    for(int cas=1;;cas++){
        scanf("%d",&n);
        if(!n) break;
        clear();
        for(int i=1;i<=n;i++) {
            scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
            e[++tot]=edge(a,b,d,1); y[tot]=b;
            e[++tot]=edge(c,b,d,-1);  y[tot]=d;
        }
        sort(e+1,e+tot+1);
        sort(y+1,y+tot+1);
        sz=unique(y+1,y+tot+1)-(y+1);
        for(int i=1;i<=tot;i++) {
           ql=e[i].y1,qr=e[i].y2,val=e[i].v;
           add(1,1,sz);
           ans+=(e[i+1].x-e[i].x)*sum[1];
        }
        printf("Test case #%d\n",cas);
        printf("Total explored area: %.2lf\n\n",ans);
    }
    return 0;
}
View Code

据说YK她们很多年前就会做了,又想起每次去问LLJ大佬题,他总说:这个不是XXX的模板/经典/套路题嘛,我实在是太弱啦。

posted @ 2017-09-11 16:02  啊宸  阅读(105)  评论(0编辑  收藏  举报