一道非常经典的线段树简单题(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
",cas);
printf("Total explored area: %.2lf
",ans);
}
return 0;
}
据说YK她们很多年前就会做了,又想起每次去问LLJ大佬题,他总说:这个不是XXX的模板/经典/套路题嘛,我实在是太弱啦。