可以看看这里: http://www.cnblogs.com/Booble/archive/2010/10/10/1847163.html

为了写扫描线, 大概写了有史以来最丑的线段树了。

poj 1177 && hdu 1828 都是求矩形周长并,周长并改一改就可以求面积并了。

其实思想并不复杂,将x维排序,将x维上的2n条线段作为事件,每个事件统计与上个事件之间的所占周长长度。

统计周长长度有点烦, 在y维上要用线段树维护: 共有多长的线段被覆盖,以及共有多少“团”线段。

每次加的答案就是 : 覆盖值得改变量 + (当前线段与前一线段的距离) * 2 * (线段"团"数);

至于线段树,离散之后我维护了六个标记(貌似有神犇只要用三个标记+.+),而且合并的时候写的十分丑陋;

维护了这么六个值: 该区间覆盖最小值,最小值是否在左区间/右区间,最小值出现次数以及团数,以及为了维护最小值而保留的另一个标记。

反正就是很丑,写了5KB,难得有线段树写的这么丑。

# include <cstdio>
# include <cstdlib>
# include <cmath>
# include <cstring>using namespace std;const int maxn = 7000;
int len[maxn*2], old[maxn*2],left[maxn], right[maxn], low[maxn],high[maxn];
int newlow[maxn], newhigh[maxn], num[maxn*2], id[maxn*2];
int bj[maxn*4], tmin[maxn*4], tot[maxn*4], repeat[maxn*4];
bool covl[maxn*4], covr[maxn*4];int top, mat, ans, h, st, n, i;void sort(int l, int r)
{int i = l, j = r, d = num[(l + r) >> 1], dj = id[(l + r) >> 1] % 2,tmp;for (;i <= j;){for (;(num[i] < d) || (num[i] == d && (id[i] % 2) < dj);i++);for (;(num[j] > d) || (num[j] == d && (id[j] % 2) > dj);j--);if (i <= j)tmp = num[i], num[i] = num[j], num[j] = tmp,tmp = id[i], id[i] = id[j], id[j] = tmp, i++, j--;}if (i < r) sort (i, r);if (l < j) sort (l, j);
}void prepare_y()
{int i; mat = 1,  top = 0;for (i = 1; i <= n; i++){num[++top] = low[i], id[top] = i * 2;num[++top] = high[i], id[top] = i * 2 +1; }sort(1, top);for (i = 1; i <= top; i++){if (num[i] != num[i - 1]) mat++;if ((id[i] & 1) == 0 ) newlow[id[i] >> 1] = mat, old[mat] = low[id[i] >> 1];else newhigh[id[i] >> 1] = mat, old[mat] = high[id[i] >> 1]; }for (h = 0, st = 1; st <= mat + 1; st <<= 1, h ++);for (i = 1; i <= st * 2; i++) len[i] = 1; for (i = 1; i <= mat-1; i++) len[st + i] = old[i+1] - old[i];for (i = st-1; i>=1; i--) len[i] = len[i << 1]+ len[(i << 1)+1];memset(id, 0, sizeof(id));memset(num, 0, sizeof(num));
}void prepare_x()
{top = 0;for (i = 1; i <= n; i++){num[++top] = left[i], id[top] = i * 2;num[++top] = right[i], id[top] = i * 2 +1;}sort(1, top);
}void origin()
{memset(bj, 0, sizeof(bj));memset(tmin, 0, sizeof(tmin));memset(covl, true, sizeof(covl));memset(covr, true, sizeof(covr));for (int i = 1; i <= st * 2; i++) repeat[i] = 1, tot[i] = 1;for (int i = 1; i <= mat; i++)tot[i +st] = len[i+st];for (int i = st - 1; i >= 1; i--)tot[i] = tot[i << 1] + tot[(i << 1 )+1];
}int min(int x, int y)
{return x < y ? x: y;
}void up(int x)
{for (; x>= 1; x >>=1){tmin[x] = min(tmin[x << 1], tmin[(x << 1) +1]);if (tmin[x << 1] == tmin[(x << 1) +1]){repeat[x] = repeat[x << 1] + repeat[(x << 1) +1] - (covr[x << 1] && covl[(x << 1)+1]);tot[x] = tot[x << 1] + tot[(x << 1 )+1];covl[x] = covl[x << 1], covr[x] = covr[(x << 1) +1]; }else if (tmin[x << 1] < tmin[(x << 1) +1]){repeat[x] = repeat[x << 1];tot[x] = tot[x << 1];covl[x] = covl[x << 1], covr[x] = false;}else{repeat[x] = repeat[(x << 1)+1];tot[x] = tot[(x << 1) +1];covr[x] = covr[(x << 1)+1]; covl[x] = false;}}
}void down(int x)
{int i, now;for (i = h; i>0; i--){now = x >> i;if (bj[now] != 0) {bj[now << 1]+= bj[now], bj[(now << 1) +1]+= bj[now];tmin[now << 1]+= bj[now], tmin[(now << 1)+1]+= bj[now];bj[now]= 0; } }
}void change(int l, int r, int d)
{l = l+st-1, r = r+st+1;int ll = l >> 1, rr = r >> 1;down(l); down(r);for (;(l ^ r) != 1; l >>= 1, r >>= 1){if ((l & 1) == 0) bj[l+1]+=d, tmin[l+1]+=d;if ((r & 1) == 1) bj[r-1]+=d, tmin[r-1]+=d;}up(ll); up(rr);
}void help()
{for (int i = 1; i <= st; i++)down(i+st);
}int main()
{freopen("1177.in", "r", stdin);freopen("1177.out", "w", stdout);while (scanf("%d", &n) != EOF){for (i = 1; i <= n; i++)scanf("%d%d%d%d", &left[i], &low[i], &right[i], &high[i]);prepare_y();prepare_x();origin();ans = high[id[1] >> 1] - low[id[1] >> 1];change(newlow[id[1] >> 1], newhigh[id[1] >> 1]-1, 1);for (i = 2; i <= top; i++){//help();int who = id[i] >> 1;int a1 = len[1]- tot[1] , a2 = repeat[1];if ((who << 1)== id[i]) change(newlow[who], newhigh[who]-1, 1);else change(newlow[who], newhigh[who]-1, -1);int b1 = len[1]- tot[1] ;ans += abs(a1 - b1) + (num[i] - num[i-1]) * 2 * (a2 - 1); }printf("%d\n", ans);}return 0;
}

ps: hdu上居然是多组数据,贡献了六七个wa。

附带一个poj1151 求矩形面积并的, 稍微好些一点;

# include <cstdlib>
# include <cstdio>
# include <cmath>
# include <cstring>using namespace std;const int maxn = 200;
int  id[maxn];
double num[maxn], left[maxn], right[maxn], low[maxn], high[maxn], old[maxn*2], tot[maxn*4], len[maxn*4];
int  tmin[maxn*4],  bj[maxn*4], newlow[maxn], newhigh[maxn];
int  test, h, st, n, top, mat;
double ans;void sort(int l, int r)
{double d = num[(l + r)>> 1], tmpd;int i = l, j = r, tmp,  dj = id[(l + r)>> 1] & 1;for (;i <= j;){for (;num[i] < d || (num[i] == d && (id[i] & 1) < dj); i++);for (;num[j] > d || (num[j] == d && (id[j] & 1) > dj); j--);if (i <= j) tmpd=num[i], num[i]=num[j], num[j]=tmpd,tmp=id[i], id[i]=id[j], id[j]=tmp, i++,j--;  }if (i < r) sort(i, r);if (l < j) sort(l, j);
}void prepare_y()
{memset(num, 0, sizeof(num));memset(id, 0, sizeof(id));int i; top = 0; mat = 1;for (i = 1; i <= n; i++){num[++top] = low[i]; id[top] = i * 2;num[++top] = high[i]; id[top] = i * 2 + 1;}sort(1, top);for (i = 1; i <= top; i++){if (num[i] != num[i-1]) mat++;if ((id[i] & 1) == 0) newlow[id[i] >> 1] = mat, old[mat] = low[id[i] >> 1];else newhigh[id[i] >> 1] = mat, old[mat] = high[id[i] >> 1]; }for (st = 1, h = 0; st <= mat +1; st <<= 1, h++);for (i = 1; i <= st*2; i++) len[i] = 1;for (i = 1; i <= mat-1; i++) len[i+st] = old[i+1] - old[i];for (i = st-1; i >= 1; i--) len[i] = len[i << 1] + len[(i << 1)+1];
}void prepare_x()
{memset(num, 0, sizeof(num));memset(id, 0, sizeof(id));int i; top = 0; mat = 1;for (i = 1; i <= n; i++){num[++top] = left[i], id[top] = i * 2;num[++top] = right[i], id[top] = i * 2 +1;}sort(1, top);
}void origin()
{int i; ans = 0; memset(tmin, 0, sizeof(tmin));memset(bj, 0 ,sizeof(bj));for (i = 1; i <= st*2; i++) tot[i] = len[i];
}void read()
{int i; scanf("%d", &n);for (i = 1; i <= n; i++)scanf("%lf%lf%lf%lf", &left[i], &low[i], &right[i], &high[i]);prepare_y();prepare_x();origin();
}void down(int x)
{int i;for (i = h; i > 0; i--){int now = x >> i;if (bj[now] != 0){bj[now << 1]+= bj[now]; bj[(now << 1)+1]+= bj[now];tmin[now << 1]+=bj[now]; tmin[(now << 1)+1]+= bj[now];bj[now] = 0; }}
}int min(int x, int y)
{return x < y ? x:y ;
}void up(int x)
{for (;x > 0; x >>=1){tmin[x] = min(tmin[x << 1], tmin[(x << 1)+1]);if (tmin[x << 1] == tmin[(x << 1)+1]) tot[x] = tot[x << 1] + tot[(x << 1)+1];else if (tmin[x << 1] < tmin[(x << 1)+1]) tot[x] = tot[x << 1];else  tot[x] = tot[(x << 1)+1];}
}void change(int l, int r, int d)
{l = l+st-1; r= r+st+1; int ll = l >> 1, rr = r >> 1;down(l); down(r);for (;(l ^ r) != 1; l>>=1, r>>=1){if ((l & 1) == 0) tmin[l+1]+= d, bj[l+1]+= d;if ((r & 1) == 1) tmin[r-1]+= d, bj[r-1]+= d;}up(ll); up(rr);
}int i;
int main()
{freopen("1151.in", "r", stdin);freopen("1151.out", "w", stdout);for (test = 1;;test++){read();if ( n == 0) break;change(newlow[id[1] >> 1], newhigh[(id[1]>>1)]-1, 1);for (i = 2; i <= top; i++){ans += (num[i] - num[i-1]) * (len[1] - tot[1]);if ((id[i] & 1) == 0) change(newlow[id[i] >> 1], newhigh[(id[i]>>1)]-1, 1);else change(newlow[id[i] >> 1], newhigh[(id[i]>>1)]-1, -1);}printf("Test case #%d\n", test);printf("Total explored area: %.2lf\n\n", ans);}return 0;
}

【扫描线法】 poj 1177 hdu 1828相关推荐

  1. Picture POJ - 1177(矩形周长并))

    Picture POJ - 1177 题目: 多个矩阵相交在一起,问新图形的周长是多少 题解: 参考题解 周长分为两部分:横线和竖线 横线计算方法:现在总区间被覆盖的长度和上一次总区间被覆盖的长度之差 ...

  2. 线段树辅助——扫描线法计算矩形面积并

    线段树辅助--扫描线法计算矩形面积并 本篇文章转自:传送门 分析: 1.矩形比较多,坐标也很大,所以横坐标需要离散化(纵坐标不需要),熟悉离散化后这个步骤不难,所以这里不详细讲解了,不明白的还请百度 ...

  3. POJ 3278 / hdu 2717 Catch That Cow (广搜)

    POJ 3278 HDU 2717 广搜题,用一个数组标记就可以过,不标记的话会超内存. 另外,poj的数据要比hdu强一些,比如0 100,这种数据.不特判的话会RE.不过如果不特判,在poj上用C ...

  4. POJ 1177 Picture [离散化+扫描线+线段树]

    http://poj.org/problem?id=1177 给若干矩形,求被覆盖的区域的周长. 将 y 坐标离散化后,按 x 坐标进行扫描.用线段树维护两个东西,当前竖线的叠加长度 len 和 条数 ...

  5. HDU 1828:Picture(扫描线+线段树 矩形周长并)

    题目链接 题意 给出n个矩形,求周长并. 思路 学了区间并,比较容易想到周长并. 我是对x方向和y方向分别做两次扫描线.应该记录一个pre变量,记录上一次扫描的时候的长度,对于每次遇到扫描线统计答案的 ...

  6. poj 1177 线段树+离散化+扫描线 求矩形并的轮廓长

    Picture 题意:求矩形面积并额轮廓长 解法:扫描线+离散化+线段树 做法:等于更新操作前后的tree[1].len差,做法这么巧妙实际我也不知道为什么.差不多的意思就是更新操作的cover变化长 ...

  7. Picture HDU - 1828 (扫描线求矩形周长并)

    题目连接:https://cn.vjudge.net/problem/HDU-1828 题意:给你n个矩形,让你求矩形的轮廓的周长之和 两遍扫描线从左到右,从下到上即可. #include <i ...

  8. HDU 1828 线段树之扫描线之周长并

    点击打开链接 题意:给n个矩形,求它们重叠后的周长 思路:用线段树的扫描线从下到上扫一遍,与面积并思想有些相似面积并,下面重边的处理相似,但是周长的并需要求的是竖边的个数然后乘以高度,而面积并求的是底 ...

  9. hdu 1828 pku 1177 Picture

    这困扰我N久的题目,终于过了. 求N个矩形的周长并,一开始觉得太遥不可及了,感觉好复杂 ,总想先搞懂计算的方法,再看大牛的方法,可是N久之后,对那个方法还是一知半解: 今天结合了代码还有下面俩副图之后 ...

最新文章

  1. 为什么我们总认为开源不挣钱?
  2. “SQL Server does not allow remote connections”错误的解决
  3. insert在python中的用法_python中insert用法是什么_后端开发
  4. Office2003与Office2007默认打开方式的切换
  5. Asp组件初级入门与精通系列之六
  6. 使用Opencv将RGB颜色空间转换到HSV颜色空间/灰度图
  7. dojo实现省份地市级联---省份数据源
  8. Android VLC 加载ass字幕乱码问题
  9. 干货分享:PDF分割合并工具免费哪个好用?
  10. android 设置自动曝光,我应该如何设置自定义的相机,曝光和白平衡值,如果在Android定制camera.Does初始化相机参数时,相机自动处理这些我不设置曝光和白平衡或者我需要...
  11. 同步模式之保护性暂停
  12. 解决win10睡眠后变卡的问题
  13. 控制反转和依赖注入/ scop
  14. 20230106 作业
  15. SIMD和SPMD的区别
  16. STM32F411核心板固件库开发(四) ADC配置
  17. 使用react 写一个 仿淘宝 图片放大镜效果
  18. TP3.2 如何设置 防跳墙访问
  19. Docker构建JDK 镜像
  20. CVPR:将X光图片用于垃圾分割,探索大规模智能垃圾分类

热门文章

  1. jQueryAjax学习笔记
  2. python 图标字体_Python+PyQt:使用图标字体打造无边框通用导航界面
  3. 使用ARIMA进行股票预测
  4. 区块链能否与数字货币彻底分离 区块链软件开发公司
  5. 千里眼摄像头支持对象存储吗_“无处安放”的海量数据,万能的对象存储
  6. 【光纤通信课程-每周一练(含答案)】第九周—波分复用系统
  7. TCP头部分析与确认号的理解
  8. java 考证资料_Java认证考试资料(ATA)
  9. 系统试运行报告是谁写的_地表水水质自监测站验收报告编制
  10. 在Fedora 12 下安装Intel X4500 显卡驱动