题意大概就是上图这个样子。<=100组测试数据,每组<=1000个矩形。

题解:

这个问题怎么解决。。做了上一题矩形面积并应该就会了。。

对于每个节点维护3个值:

cnt:该节点所代表的这条线段被覆盖了多少次

len1:该节点所管理区间中被覆盖了>=1次的线段总长

len2:该节点所管理区间中被覆盖了>=2次的线段总长

为什么要维护两个呢?因为要是只维护len2,那子树中要是有个覆盖了一次的,然后该节点覆盖一次,那么怎么更新len2丫。。

怎么更新?

 void upd(int x)
{
int lc=t[x].lc,rc=t[x].rc;
if(t[x].cnt>=) //如果该点被覆盖了两次
t[x].len1=t[x].len2=t[x].rl;//len1和len2=该节点所代表线段的长度
if(t[x].cnt==)//如果该点只被覆盖了一次
{
t[x].len1=t[x].rl;//len1=全长
t[x].len2=t[lc].len1+t[rc].len1;//孩子中有些只被覆盖了一次的变成覆盖了两次
}
if(t[x].cnt==)//如果没被覆盖,那就直接上传更新。
{
t[x].len1=t[lc].len1+t[rc].len1;
t[x].len2=t[lc].len2+t[rc].len2;
}
}

一开始我在纠结一种情况:一个节点现在被覆盖一次,它的子树中原本有个节点被覆盖了一次,那么怎么更新?维护一个从根节点往下的sum值吗?

后来我发现该节点的len2可以直接用孩子的len1更新就好。

弱弱弱弱弱弱弱弱弱弱弱弱弱弱弱弱

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std; const int N=,INF=(int)1e9;
double z[N][];
struct point{
double d;
int x,y;
}p[*N];
struct node{
int x0,x1,d;
double y;
}a[N];
struct trnode{
int l,r,lc,rc,cnt,lazy;
double rl,len1,len2;
//len1以x为根的子树中表示被覆盖了>=1次的线段长度,len2表示以x为根的子树中被覆盖了>=2次的线段的长度
}t[*N];
double num[N];
int n,tl,pl,al; int minn(int x,int y){return x<y ? x:y;}
int maxx(int x,int y){return x>y ? x:y;}
bool cmp_d(point x,point y){return x.d<y.d;}
bool cmp_y(node x,node y){return x.y<y.y;} int bt(int l,int r)
{
int x=++tl;
t[x].l=l;t[x].r=r;
t[x].lc=t[x].rc=;
t[x].cnt=;t[x].lazy=;
t[x].len1=t[x].len2=;
t[x].rl=num[r+]-num[l];
if(l<r)
{
int mid=(l+r)/;
t[x].lc=bt(l,mid);
t[x].rc=bt(mid+,r);
}
return x;
} void upd(int x)
{
int lc=t[x].lc,rc=t[x].rc;
if(t[x].cnt>=) //如果该点被覆盖了两次
t[x].len1=t[x].len2=t[x].rl;//len1和len2=该节点所代表线段的长度
if(t[x].cnt==)//如果该点只被覆盖了一次
{
t[x].len1=t[x].rl;//len1=全长
t[x].len2=t[lc].len1+t[rc].len1;//孩子中有些只被覆盖了一次的变成覆盖了两次
}
if(t[x].cnt==)//如果没被覆盖,那就直接上传更新。
{
t[x].len1=t[lc].len1+t[rc].len1;
t[x].len2=t[lc].len2+t[rc].len2;
}
} void change(int x,int l,int r,int d,int sum)
{
if(t[x].l==l && t[x].r==r)
{
t[x].cnt+=d;
upd(x);
return ;
}
int lc=t[x].lc,rc=t[x].rc,mid=(t[x].l+t[x].r)/;
if(r<=mid) change(lc,l,r,d,sum+t[x].cnt);
else if(l>mid) change(rc,l,r,d,sum+t[x].cnt);
else
{
change(lc,l,mid,d,sum+t[x].cnt);
change(rc,mid+,r,d,sum+t[x].cnt);
}
upd(x);
} void output()
{
for(int i=;i<=tl;i++)
printf("l = %d r = %d cnt = %d len1 = %lf len2 = %lf rl = %lf \n",t[i].l,t[i].r,t[i].cnt,t[i].len1,t[i].len2,t[i].rl);
} int main()
{
freopen("a.in","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
if(n==) break;
int x,mx;pl=;tl=;al=;t[].len1=t[].len2=;
for(int i=;i<=n;i++)
{
for(int j=;j<=;j++)
{
scanf("%lf",&z[i][j]);
if(j%==) p[++pl].d=z[i][j],p[pl].x=i,p[pl].y=j;
}
}
sort(p+,p++pl,cmp_d);
mx=;p[].d=INF;
for(int i=;i<=pl;i++)
{
if(p[i].d!=p[i-].d) mx++,num[mx]=p[i].d;
z[p[i].x][p[i].y]=mx;
}
bt(,mx-);//debug n个节点只有n-1条线段
for(int i=;i<=n;i++)
{
if(z[i][]<z[i][]) swap(z[i][],z[i][]);
if(z[i][]>z[i][]) swap(z[i][],z[i][]);
a[++al].x0=z[i][];a[al].x1=z[i][];a[al].y=z[i][];a[al].d=-;
a[++al].x0=z[i][];a[al].x1=z[i][];a[al].y=z[i][];a[al].d=;
}
sort(a+,a++al,cmp_y);
double w,h,ans=;
change(,a[].x0,a[].x1-,a[].d,);
for(int i=;i<=al;i++)
{
h=a[i].y-a[i-].y;
w=t[].len2;
ans+=w*h;
change(,a[i].x0,a[i].x1-,a[i].d,);
}
printf("%.2lf\n",ans);
}
return ;
}

【hdu1255】线段树求矩形面积交的更多相关文章

  1. HDU - 1255 覆盖的面积(线段树求矩形面积交 扫描线+离散化)

    链接:线段树求矩形面积并 扫描线+离散化 1.给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. 2.看完线段树求矩形面积并 的方法后,再看这题,求的是矩形面积交,类同. 求面积时,用被覆 ...

  2. POJ 1151 / HDU 1542 Atlantis 线段树求矩形面积并

    题意:给出矩形两对角点坐标,求矩形面积并. 解法:线段树+离散化. 每加入一个矩形,将两个y值加入yy数组以待离散化,将左边界cover值置为1,右边界置为2,离散后建立的线段树其实是以y值建的树,线 ...

  3. 【hdu1542】线段树求矩形面积并

    分割线内容转载自http://hzwer.com/879.html ------------------------------------------------------------------ ...

  4. POJ 1151 Atlantis 线段树求矩形面积并 方法详解

    第一次做线段树扫描法的题,网搜各种讲解,发现大多数都讲得太过简洁,不是太容易理解.所以自己打算写一个详细的.看完必会o(∩_∩)o 顾名思义,扫描法就是用一根想象中的线扫过所有矩形,在写代码的过程中, ...

  5. POJ 1151Atlantis 扫描线+线段树求矩形面积并

    题目链接 #include <iostream> #include <vector> #include <cstdio> #include <cstring& ...

  6. UVA 11983 Weird Advertisement --线段树求矩形问题

    题意:给出n个矩形,求矩形中被覆盖K次以上的面积的和. 解法:整体与求矩形面积并差不多,不过在更新pushup改变len的时候,要有一层循环,来更新tree[rt].len[i],其中tree[rt] ...

  7. HDU 1542.Atlantis-线段树求矩形面积并(离散化、扫描线/线段树)-贴模板

    好久没写过博客了,这学期不是很有热情去写博客,写过的题也懒得写题解.现在来水一水博客,写一下若干年前的题目的题解. Atlantis Time Limit: 2000/1000 MS (Java/Ot ...

  8. HDU 1828 / POJ 1177 Picture --线段树求矩形周长并

    题意:给n个矩形,求矩形周长并 解法:跟求矩形面积并差不多,不过线段树节点记录的为: len: 此区间线段长度 cover: 此区间是否被整个覆盖 lmark,rmark: 此区间左右端点是否被覆盖 ...

  9. 2015 UESTC 数据结构专题E题 秋实大哥与家 线段树扫描线求矩形面积交

    E - 秋实大哥与家 Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/contest/show/59 De ...

随机推荐

  1. <Android>对话框的使用

    Android系统提供四种对话框:警告对话框(AlertDialog),进度对话框(ProgressDialog),日期选择对话框(DatePickerDialog)和时间选择对话框(TimePick ...

  2. UVA 167 R-The Sultan's Successors

    https://vjudge.net/contest/68264#problem/R The Sultan of Nubia has no children, so she has decided t ...

  3. 【log4net】- 非常完善的Log4net详细说明

    1.概述 log4net是.Net下一个非常优秀的开源日志记录组件.log4net记录日志的功能非常强大.它可以将日志分不同的等级,以不同的格式,输出到不同的媒介.本文主要是介绍如何在Visual S ...

  4. Android 如何判断CPU是32位还是64位

    转自:http://blog.csdn.net/wangbaochu/article/details/47723265 1. 读取Android 的system property ("ro. ...

  5. MongoDb企业应用实战(一) 写在MongoDB应用介绍之前(ii)

    上一篇: MongoDb企业应用实战(一) 写在MongoDB应用介绍之前(i) 有段时间没跟大家去分享和探讨过一些问题,分享过一些经验了(失败过的,痛苦过的才最有看点啊,不知道各位同仁们怎么去看这个 ...

  6. Python爬虫requests判断请求超时并重新发送请求

     下面是简单的一个重复请求过程,更高级更简单的请移步本博客: https://www.cnblogs.com/fanjp666888/p/9796943.html  在爬虫的执行当中,总会遇到请求连接 ...

  7. input 元素 相对父元素错位

    <div class="recommend"> <i class="iconfont icon-user"></i> < ...

  8. 【swaggerui】swaggerui在asp.net web api core 中的应用

    Swaggerui 可以为我们的webapi提供美观的在线文档,如下图: 实现步骤: NuGet Packages  Install-Package Swashbuckle.AspNetCore 在s ...

  9. hdu 1596 find the safest road (最短路径)

    find the safest road Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot ...

  10. Codeforces Round #466 (Div. 2) E. Cashback

    Codeforces Round #466 (Div. 2) E. Cashback(dp + 贪心) 题意: 给一个长度为\(n\)的序列\(a_i\),给出一个整数\(c\) 定义序列中一段长度为 ...