题目链接:
POJ:http://poj.org/problem?id=1177
HDU:http://acm.hdu.edu.cn/showproblem.php?pid=1828
几个不错的讲解:
http://www.cnblogs.com/scau20110726/archive/2013/04/13/3018702.html
http://blog.csdn.net/xingyeyongheng/article/details/8931410
Description
Input
Output
Sample Input
7 -15 0 5 10 -5 8 20 25 15 -4 24 14 0 -6 16 4 2 15 10 22 30 10 36 20 34 0 40 16
Sample Output
228
Source
题目链接:
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> using namespace std; #define N 5017 #define MAX 10100 #define ll root*2 #define rr root*2+1 //#define mid (a[root].l+a[root].r)>>1 struct Line { int l, r; int h;//高度 int flag;//若该扫描线属于矩形的下边的横边,则叫做入边,值为1,若属于矩形的上边的横边,则叫做出边,值为-1 } line[N*2]; struct node { int l, r; int lp, rp;//是一个标记量,只有0,1,表示这个节点左右两个端点没有被覆盖,有为1,无为0 int num;//这个区间被多少条线段覆盖 int cover;//表示某x轴坐标区间内是否有边覆盖 int len;//区间覆盖边长度 } a[2*MAX*4]; bool cmp(Line a,Line b) { return a.h < b.h; } void build(int left,int right,int root)//构造线段树 { a[root].l = left; a[root].r = right; a[root].cover = 0; a[root].len = 0; a[root].lp = a[root].rp = a[root].num=0; if(left == right) return; int mid = (a[root].l+a[root].r)>>1; build(left,mid,ll); build(mid+1,right,rr); } void pushup(int root) { if(a[root].cover) { a[root].len = a[root].r-a[root].l+1; a[root].lp = a[root].rp = 1; a[root].num = 1; } else if(a[root].l == a[root].r)//叶子 { a[root].len = 0; a[root].lp = a[root].rp = 0; a[root].num = 0; } else { a[root].len = a[ll].len+a[rr].len; a[root].lp = a[ll].lp; a[root].rp = a[rr].rp; a[root].num = a[ll].num + a[rr].num - (a[ll].rp&a[rr].lp); } } void update(int left,int right,int val,int root)//加入线段e,后更新线段树 { if(left > right) return; if(a[root].l==left && a[root].r==right)//目标区间 { a[root].cover+=val;//插入或删除操作直接让cover[]+=flag。当cover[]>0时,该区间一定有边覆盖。 pushup(root); return; } int mid = (a[root].l+a[root].r)>>1; if(right <= mid) update(left,right,val,ll); else if(left > mid) update(left,right,val,rr); else { update(left,mid,val,ll); update(mid+1,right,val,rr); } pushup(root); } int main() { int n, i, k; while(scanf("%d",&n)!=EOF) { if(n == 0) { printf("0\n"); continue; } k = 0; int x1, y1, x2, y2; int maxx = -MAX;//方便此题建树 int minn = MAX; for(i = 0; i < n; i++) { scanf("%d%d%d%d",&x1,&y1,&x2,&y2); //本题采用平行x轴的扫描线从下往上扫描 maxx = max(maxx, x2); minn = min(minn, x1); line[k].l = x1; line[k].r = x2; line[k].h = y1; line[k].flag = 1; line[k+1].l = x1; line[k+1].r = x2; line[k+1].h = y2; line[k+1].flag = -1; //把图中的边用line存起来以便排序 k += 2; } sort(line,line+k,cmp); build(minn, maxx-1, 1); int ans = 0; int prelen = 0; line[k] = line[k+1];//每次处理循环的最后一次 for(i = 0; i < k; i++) { update(line[i].l,line[i].r-1,line[i].flag,1);//每插入一次就算一次 ,相对应的边在线段树中会抵消 //ans+=(line[i+1].h-line[i].h)*a[1].len;//高 X 低 ans += abs(a[1].len - prelen); //计算横线部分 ans += (line[i+1].h-line[i].h) * (2*a[1].num); //计算竖线部分 prelen = a[1].len;//之前的长度 } printf("%d\n",ans); } return 0; }