学习了一种新的离散化
第一次写有关线段的线段树
个人理解的扫描线:每添加一条边(或权值)就算当前这一部分的东西,然后再添加,一个循环
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 200
int n,T,t;
double x1,x2,y1,y2,ans;
struct point{
double x,y1,y2;
int flag;
}node[2*MAXN];
struct tpoint{
int l,r,s;
double len,ml,mr;
}tree[4*MAXN];
double y[2*MAXN];
int comp(const point &a,const point &b)
{
return a.x<b.x+0.00000001;
}
//tree[p].len表示tree[p].ml~tree[p].mr之间被线段覆盖的总长度
//tree[p].s表示tree[p].ml~tree[p].mr之间被几条线段覆盖
//并且tree[p].s>0表示这条线段被完全覆盖
void build(int p,int l,int r)
{
tree[p].l=l;
tree[p].r=r;
tree[p].ml=y[l];//离散化
tree[p].mr=y[r];
tree[p].s=0;
tree[p].len=0;
if (tree[p].l+1==tree[p].r)
return ;
int mid=(l+r) >> 1;
build(p<<1,l,mid);
build(p<<1^1,mid,r);
}
void callen(int p)//算tree[p].len
{
if (tree[p].s>0)
tree[p].len=tree[p].mr-tree[p].ml;
else
if (tree[p].l+1==tree[p].r)
tree[p].len=0;
else
tree[p].len=tree[p<<1].len+tree[p<<1^1].len;
return ;
}
void updata(int p,point t)
{
if (tree[p].ml==t.y1 && tree[p].mr==t.y2)
{
tree[p].s+=t.flag;
callen(p);
return ;
}
double mid=tree[p<<1].mr;
if (t.y2<=mid) updata(p<<1,t);
if (t.y1>=mid) updata(p<<1^1,t);
if (t.y1<mid && t.y2>mid)
{
point tmp=t;
tmp.y2=mid;
updata(p<<1,tmp);
tmp=t;
tmp.y1=mid;
updata(p<<1^1,tmp);
}
callen(p);//每一次更新了tree[p]的子节点,就要更新p的len,保证每次只取tree[1].len即可
return ;
}
int main()
{
while (scanf("%d", &n) && (n))
{
T++;
t=0;
for (int i=1;i<=n;i++)
{
scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
t++;
y[t]=y1;
node[t].x=x1;
node[t].y1=y1;
node[t].y2=y2;
node[t].flag=1;
t++;
y[t]=y2;
node[t].x=x2;
node[t].y1=y1;
node[t].y2=y2;
node[t].flag=-1;
}
sort(node+1,node+t+1,comp);
sort(y+1,y+t+1);
build(1,1,t);
ans=0;
updata(1,node[1]);
for (int i=2;i<=t;i++)
{
ans+=(node[i].x-node[i-1].x)*tree[1].len;
updata(1,node[i]);
}
printf("Test case #%d\n",T);
printf("Total explored area: %.2lf\n\n",ans);
}
return 0;
}