线段树+扫描线求矩形并的周长
求矩形的并的周长依然是利用扫描线计算横线的长度需要考虑的就是重合的情况,我们每次计算当前扫过后覆盖的长度,然后减去上一次覆盖的长度的绝度之,就是这一次的增加量
然后对于y轴的长度我们需要知道有几个分开的区间段,假设有m个我们的增量就是 2 * m * △y,有一个缺陷如果2 3 和 3 4都被覆盖那么会误认为两个所以,我们用lbd,rbd表示当前区间的左右边界是否被覆盖那么我们pup的时候就能去更新维护一下了
好了,上代码:常规的对扫扫描线的存储
#include <iostream> #include <cstdio> #include <string.h> #include <algorithm> #include <cmath> #define eps 1e-8 #define lson rt<<1,left,mid #define rson rt<<1|1,mid,right using namespace std; const int maxn = 2e4 + 10; struct edge{ double x1,x2,y; int flag; edge(){} edge(double x1,double x2,double y,int flag):x1(x1),x2(x2),y(y),flag(flag){} bool operator < (const edge &rhs) const{ if(y == rhs.y)return flag > rhs.flag; return y < rhs.y; } }e[maxn << 1];
对于线段树的存储
cnt是覆盖的标记,line是为了计算竖向的周长来记录的区间个数n * 2
lbd,rbd是区间边界覆盖标记
m是覆盖的长度
struct node{ int cnt; int line; bool lbd,rbd; double m; }tree[maxn << 2];
//离散化 double X[maxn<<1];
精华就是更新的部分
1》如果被覆盖二话不说line = 2,lbd = rbd = true,m = X[right] - X[left]
2》没有被覆盖
2.1》是叶子结点lbd = rbd = false,m = 0,line = 0;
2.2》非叶子节点lbd = rt << 1 .lbd,rbd = rt<<1|1.rbd,line = rt<<1.line + rt<<1|1.line,m = rt<<1.m+rt<<1|1.m
PS:这里要特殊判断一下如果左边孩子节点的rbd和右边孩子节点的lbd都显示被true,那么line -= 2
void pup(int rt,int left,int right) { if(tree[rt].cnt) { tree[rt].lbd = tree[rt].rbd = true; tree[rt].m = X[right] - X[left]; //printf("Find : left = %.2f right = %.2f len = %.2f\n",X[left],X[right],tree[rt].m); tree[rt].line = 2; } else if(left + 1 == right)//叶子节点且没有覆盖 { tree[rt].m = 0.0; tree[rt].lbd = tree[rt].rbd = false; tree[rt].line = 0; } else { tree[rt].lbd = tree[rt<<1].lbd; tree[rt].rbd = tree[rt<<1|1].rbd; tree[rt].m = tree[rt<<1].m + tree[rt<<1|1].m; tree[rt].line = tree[rt<<1].line + tree[rt<<1|1].line; if(tree[rt<<1].rbd && tree[rt<<1|1].lbd)tree[rt].line -= 2; } }
剩下的就差不多啦
void build(int rt,int left,int right) { tree[rt].cnt = 0; tree[rt].line = 0; tree[rt].m = 0.0; tree[rt].lbd = false; tree[rt].rbd = false; if(left + 1 == right)return; int mid = (left + right) >> 1; build(lson); build(rson); } bool Equal(double x,double y) { return abs(x - y) <= eps; } void update(double l,double r,int v,int rt,int left,int right) { if(Equal(l,X[left]) && (Equal(r,X[right]))) { tree[rt].cnt += v; pup(rt,left,right); return; } if(left + 1 == right)return; int mid = (left + right) >> 1; if(r <= X[mid] + eps)update(l,r,v,lson); else if(l >= X[mid] -eps)update(l,r,v,rson); else { update(l,X[mid],v,lson); update(X[mid],r,v,rson); } pup(rt,left,right); } int main() { int n; double x1,y1,x2,y2; while(~scanf("%d",&n)) { for(int i = 0;i < n;++i) { scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); e[i] = edge(x1,x2,y1,1); e[i + n] = edge(x1,x2,y2,-1); X[i] = x1; X[i+n] = x2; } n <<= 1; sort(X,X+n); sort(e,e+n); int N = unique(X,X+n) - X; build(1,0,N-1); double now = 0.0; double last = now; for(int i = 0;i < n;++i) { update(e[i].x1,e[i].x2,e[i].flag,1,0,N-1); if(i != n-1) now += tree[1].line * (e[i+1].y - e[i].y); //cout<<now<<endl; now += abs(tree[1].m - last); //cout<<now<<endl; //printf("now line: %.2f --- %.2f\n",e[i].x1,e[i].x2); //if(i != n-1) //printf("last line: %.2f --- %.2f\n",e[i-1].x1,e[i-1].x2); //printf("now len : %.2f\n",tree[1].m); //printf("last len : %.2f\n",last); //cout<<now<<endl; //printf("%d : %.2f\n",i+1,abs(tree[1].m - last)); last = tree[1].m; } printf("%.0f\n",now); } return 0; }