hdu1828线段树+扫描线
来源:互联网 发布:捷通人才系统源码 编辑:程序博客网 时间:2024/04/30 12:17
http://acm.hdu.edu.cn/showproblem.php?pid=1828
(矩形求周长类似矩形合并求面积,只是多了需要统计竖边的个数,对于每次求到的下底边长还要增加目前底边与下一条底边之间的竖边总长)
1,n个矩形有2*n条线段,按从小到大排列,如上图得到的线段顺序
2:
开始扫描第一条线段,得到总底边长sum为a这部分,得到竖边个数segnum=2,(每增加一条底边segnum+=2,每合并一条底边segnum-=2,无下底边比上底边多segnum=0)
于是得到一部分周长如图蓝色部分:
3:扫描第2条线段:
得到新的底边sum=a+b,则新增加的底边周长为sum-last,(last记录的是上一次的底边)
X表示该竖边被合并了segnum-=2,(由于底边合并了),所以segnum还是为2
则新增加周长为新增加的蓝色部分:
后面同理继续扫描
如果扫描到了上底边,则底边总长会相应的减少该上底边的长度,则abs(sum-last)就是增加上底边的长度
这里说下扫描周长时不像扫描面积一样只需扫描到第2n-1条线段就行
而是要扫描整个2n条线段,因为扫描底2n条线段时肯定是上底边,得到的下底边总长sum=0,但是abs(sum-last)就是增加这条上底边的长度
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<queue>#include<algorithm>#include<map>#include<cmath>#include<iomanip>#define INF 99999999using namespace std;const int MAX=20000+10;int sum[MAX<<2];//统计下底边总长度int segnum[MAX<<2];//统计没有被覆盖的竖边个数bool lseg[MAX<<2],rseg[MAX<<2];//表示某个区间最左边和最右边是否有下底边多于上底边int mark[MAX<<2];//表示下底边比上底边多的个数 struct seg{int l,r,h,d;seg(){}seg(int x1,int x2,int H,int c):l(x1),r(x2),h(H),d(c){}bool operator <(const seg&a)const{if(h == a.h)return d>a.d;//这里一定不能去掉,比如这组数据:2 0 0 4 4 0 4 4 8return h<a.h;}}s[MAX];void Upfather(int n,int left,int right){if(mark[n]){sum[n]=right-left+1;lseg[n]=rseg[n]=true;segnum[n]=2;//该区间被一条底边全部覆盖,可用竖边为2 }else if(left == right)sum[n]=lseg[n]=rseg[n]=segnum[n]=0;else{sum[n]=sum[n<<1]+sum[n<<1|1];segnum[n]=segnum[n<<1]+segnum[n<<1|1];lseg[n]=lseg[n<<1];rseg[n]=rseg[n<<1|1];if(rseg[n<<1] && lseg[n<<1|1])segnum[n]-=2;//两个矩形相交(底边区域有重合)则减少两条竖边 }}void Update(int L,int R,int d,int n,int left,int right){if(L<=left && right<=R){mark[n]+=d;Upfather(n,left,right);return;}int mid=left+right>>1;if(L<=mid)Update(L,R,d,n<<1,left,mid);if(R>mid)Update(L,R,d,n<<1|1,mid+1,right);Upfather(n,left,right);}int main(){int n,x1,x2,y1,y2;while(cin>>n){int k=0,left=INF,right=-INF;for(int i=0;i<n;++i){cin>>x1>>y1>>x2>>y2;s[k++]=seg(x1,x2,y1,1);s[k++]=seg(x1,x2,y2,-1);left=min(left,x1);right=max(right,x2);}sort(s,s+k);int ans=0,last=0;for(int i=0;i<k;++i){if(s[i].l<s[i].r)Update(s[i].l,s[i].r-1,s[i].d,1,left,right);ans+=segnum[1]*(s[i+1].h-s[i].h);//竖边增加的总长ans+=abs(sum[1]-last);//底边增加的总长last=sum[1]; }printf("%d\n",ans);}}
- hdu1828线段树+扫描线
- 线段树扫描线(周长并)hdu1828
- hdu1828线段树扫描线求周长
- hdu1828 Picture(扫描线+矩形周长并+线段树)
- hdu1828&poj1177(线段树求矩形交周长,扫描线)
- hdu1828 线段树扫描线求矩形面积的周长
- hdu1828(线段树+扫描线求周长)
- hdu1828 Picture (线段树+扫描线)(求周长并)
- HDU1828 Picture(线段树+扫描线求周长并)
- POJ 1177&&HDU1828 Picture 线段树+扫描线
- hdu1828-Picture 线段树+扫描线 求周长并
- hdu1828 Picture(线段树+扫描线+矩形周长并)
- 线段树+扫描线两题hdu1542 hdu1828
- hdu1828 Picture(线段树+离散化+扫描线)两种方法
- hdu1828 Picture 扫描线
- 线段树 hdu1828 Picture
- Picture(hdu1828,求周长并,线段树+离散化+扫描)
- HDU1828 Picture 周长并 线扫描
- x86处理器中的AX BX与CX DX寄存器
- Python 学习第一天
- Oracle的JDBC驱动的版本
- Java操作Hbase2
- 【PHP5权威指南】读书心得二——高级面向对象编程和设计模式
- hdu1828线段树+扫描线
- ASP.NET性能优化之构建自定义文件缓存
- IOS开发(91)之ZBar 条形码二维码扫描控件
- NDK Command
- Remainder Calculator-指数循环结+欧拉函数
- linux C之rename() & remove()
- Java操作Hbase3
- 数据库权限设计—学习
- linux shell中特殊字符的意义$0 $1 $$ $# $@