poj1177

(题目链接)

1.扫描线

题意

  求矩形周长并。

Solution

  转自

  先看图:

  

  为了解决这个问题 我们先把一坨一坨的矩形 进行矩形切割:

  

  

  

  我们考虑周长由哪些部分构成

  其中,红线是需要统计入周长的竖边,绿线是需要统计入周长的横边

  我们称两条蓝线之间的部分为统计区间

  我们需要依次统计从左到右的统计区间内的需要计数的矩形边,累加

  形象地讲,就是用一根扫描线,从左到右依次扫描

  具体实现就是依次遍历那些蓝线然后,累加每个区间的统计结果

  我们任取2个统计区间进行详细讨论,放大前2个统计区间部分

  

  考虑为什么同样是矩形边,红边需要统计而棕色的边不需要统计

  我们发现深红色的边包含在第一个矩形内部,也就是夹在第一个矩形两条红边之间

  继续分析,我们可以知道,横边也是这样

  深蓝色边加在统计区间内的两条绿色边之间,属于矩形内部,不需要统计

  那么,如何判定是否是红边或绿边呢?

  我们在扫描线上投下当前经过扫描线矩形的投影

  

  红边必然造成投影的变化,绿边必然在投影上线段的端点处

  没有造成投影变化的竖边,肯定在投影内部,也就是在还未扫描完的矩形内部

  

   不在投影线段段端点处的横边 也会夹在在投影线段端点处的两个矩形边内

   

  于是,我们将绿边的长度=统计区间宽*投影连续段数*2

  再与红边的长度=与上一个区间投影的差求和,即得到当前区间的统计值,再累加即可

  考虑怎么统计答案,我们采用线段树

  先将一个矩形一分为二,分别记录下左竖边,右竖边,差分。将竖边按照左端点排序,扫描线从左到右扫描,依次将竖边所在的区间加入线段树,统计答案。

  用线段树记录下扫描线上的投影的情况

  当扫描线碰到举行左边的时候就插入这个线段,碰到矩形右边就删除这个线段(差分)

  我们还要重新规划在线段树上的域:覆盖次数cov[],连续段数num[],长度len[](即被覆盖的总长度)

  这几个域需要我们实时维护,更需增加维护的域ls[],rs[]表示左右端点是否被覆盖

  于是问题至此就差不多解决了,注意我们线段树上记录的是区间而不是端点,这样更方便我们统计答案。

细节

  左右下标。

2.线段树

  1. 离散化:下面的代码是对y进行离散,根据y排序去重后建树
  2. 将竖边加入数组,记录入边和出边,根据x排序
  3. 通过二分查找找到边纵坐标所在下标
  4. 处理后计算周长

代码(线段树)

  1 #include <iostream>
  2 #include <string>
  3 #include <cstdlib>
  4 #include <cmath>
  5 #include <cstdio>
  6 #include <algorithm>
  7 using namespace std;
  8 const int MAX=10010;
  9 struct node
 10 {
 11     int a,b,sum,len,f,num;
 12     bool l,r;
 13     node* x,*y;
 14 }*d,ld[MAX*4];
 15 struct Node
 16 {
 17     int s,t,x,f;
 18 }e[MAX];
 19 int dx[MAX];
 20 int t=0,n,l=0,ls=0,top=1;
 21 bool cmp(const Node &a,const Node &b)
 22 {
 23     return a.x<b.x||(a.x==b.x&&a.s<b.s);
 24 }
 25 void build(node *&d,int a,int b)
 26 {
 27     int mid=(a+b)>>1;
 28     t++;d=&ld[t];
 29     d->a=a;d->b=b;d->f=0;
 30     d->sum=0;d->num=0;d->len=dx[b]-dx[a];
 31     d->l=false;d->r=false;
 32     if(b-a==1)return;
 33     build(d->x,a,mid);build(d->y,mid,b);
 34 }
 35 void get_len(node *&d)
 36 {
 37     if(d->f>0)
 38     {
 39         d->sum=d->len;
 40         return;
 41     }
 42     if(d->b-d->a>1)
 43     {
 44         d->sum=d->x->sum+d->y->sum;
 45         return;
 46     }
 47     d->sum=0;
 48 }
 49 void get_num(node *&d)
 50 {
 51     if(d->f>0)
 52     {
 53         d->l=true;d->r=true;d->num=1;
 54     }
 55     else if(d->b-d->a>1)
 56     {
 57         d->l=d->x->l;d->r=d->y->r;
 58         d->num=d->x->num+d->y->num-d->x->r*d->y->l;
 59     }
 60     else
 61     {
 62         d->l=false;d->r=false;d->num=0;
 63     }
 64 }
 65 void change(node *&d,int a,int b,int f)
 66 {
 67     int mid=(d->a+d->b)>>1;
 68     if(d->a==a&&d->b==b)
 69     {
 70         d->f+=f;
 71         get_len(d);
 72         get_num(d);
 73         return;
 74     }
 75     if(b<=mid)
 76     {
 77         change(d->x,a,b,f);
 78     }
 79     else if(a>=mid)
 80     {
 81         change(d->y,a,b,f);
 82     }
 83     else
 84     {
 85         change(d->x,a,mid,f);
 86         change(d->y,mid,b,f);
 87     }
 88     get_len(d);
 89     get_num(d);
 90 }
 91 int main()
 92 {
 93     scanf("%d",&n);
 94     for(int i=1,a,b,c,d;i<=n;i++)
 95     {
 96         scanf("%d%d%d%d",&a,&b,&c,&d);
 97         dx[i*2-1]=b;dx[i*2]=d;
 98         e[i*2].s=b;e[i*2-1].s=b;
 99         e[i*2].t=d;e[i*2-1].t=d;
100         e[i*2].x=c;e[i*2-1].x=a;
101         e[i*2].f=-1;e[i*2-1].f=1;
102     }
103     sort(dx+1,dx+n*2+1);
104     sort(e+1,e+n*2+1,cmp);
105     for(int i=2;i<=2*n;i++)
106     {
107         if(dx[i]!=dx[top])
108         {
109             top++;dx[top]=dx[i];
110         }
111     }
112     build(d,1,top);
113     for(int i=1,a,b;i<2*n;i++)
114     {
115         a=lower_bound(dx+1,dx+top+1,e[i].s)-dx;
116         b=lower_bound(dx+1,dx+top+1,e[i].t)-dx;
117         change(d,a,b,e[i].f);
118         l=l+abs(d->sum-ls);
119         l=l+d->num*2*(e[i+1].x-e[i].x);
120         ls=d->sum;
121     }
122     int a,b;
123     a=lower_bound(dx+1,dx+top+1,e[2*n].s)-dx;
124     b=lower_bound(dx+1,dx+top+1,e[2*n].t)-dx;
125     change(d,a,b,e[2*n].f);
126     l=l+abs(d->sum-ls);
127     printf("%d",l);
128     return 0;
129 }

代码(扫描线)

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf 2147483640
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;
   
const int maxn=20010;
struct tree {int l,r,len,ls,rs,num,cov;}tr[maxn<<2];
struct data {int x,l,r,val;}a[maxn];
int n;
  
void build(int k,int s,int t) {
    tr[k].l=s;tr[k].r=t;
    if (s==t) return;
    int mid=(s+t)>>1;
    build(k<<1,s,mid);
    build(k<<1|1,mid+1,t);
}
void merge(int k) {
    int l=tr[k].l,r=tr[k].r;
    if (tr[k].cov) {
        tr[k].ls=tr[k].rs=1;
        tr[k].num=2;
        tr[k].len=r-l+1;
    }
    else if (l==r) tr[k].ls=tr[k].rs=tr[k].len=tr[k].num=0;
    else {
        tr[k].num=tr[k<<1].num+tr[k<<1|1].num;
        tr[k].len=tr[k<<1].len+tr[k<<1|1].len;
        tr[k].ls=tr[k<<1].ls;tr[k].rs=tr[k<<1|1].rs;
        if (tr[k<<1].rs && tr[k<<1|1].ls) tr[k].num-=2;
    }
}
void update(int k,int s,int t,int val) {
    int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
    if (s<=l && t>=r) {tr[k].cov+=val;merge(k);return;}
    if (s<=mid) update(k<<1,s,t,val);
    if (t>mid) update(k<<1|1,s,t,val);
    merge(k);
}
bool cmpx(data a,data b) {
    return a.x<b.x;
}
int main() {
    scanf("%d",&n);
    int m=0,l=inf,r=-inf;
    for (int x1,x2,y1,y2,i=1;i<=n;i++) {
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        l=min(l,y1);r=max(r,y2);
        a[++m]=(data){x1,y1,y2,1};a[++m]=(data){x2,y1,y2,-1};
    }
    n=m;
    build(1,l,r-1);
    sort(a+1,a+1+n,cmpx);
    int ans=0;
    for (int i=1;i<=n;i++) {
        int tmp=tr[1].len;
        if (i!=1) ans+=tr[1].num*(a[i].x-a[i-1].x);
        update(1,a[i].l,a[i].r-1,a[i].val);
        ans+=abs(tr[1].len-tmp);
    }
    printf("%d",ans);
    return 0;
}
posted @ 2020-07-25 09:01  ycy123456  Views(264)  Comments(0Edit  收藏  举报