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

来源:互联网 发布:手机陀螺仪水平仪软件 编辑:程序博客网 时间:2024/06/05 14:16

http://poj.org/problem?id=1177
给若干矩形,求被覆盖的区域的周长。

y 坐标离散化后,按 x 坐标进行扫描。用线段树维护两个东西,当前竖线的叠加长度 len 和 条数 cnt 。 前一个用来计算竖直方向的周长部分,后一个用来计算水平方向的。
left[node]right[node] 来记录每个结点左端和右端是否被覆盖,用来维护 cnt

重叠的边也不能计算,这反应在对扫描线的排序上,两线重叠时入边应在出边之前。

#include<iostream>#include<cstdio>#include<cstring>#include<vector>#include<algorithm>using namespace std;#define CHD int lc = node<<1,rc = node<<1|1;#define MID int mid = (L+R)>>1;#define debug(x) cout<<"debug "<<x<<endl;#define rep(i,f,t) for(int i = (f),_end =(t); i <= _end; ++i)struct Node{    int x;    int y1,y2;    int flag; //入边为1,出边为-1    Node(int x,int y1,int y2,int f)        :x(x),y1(y1),y2(y2),flag(f){        }    bool operator< (const Node &n2)const{        if(x == n2.x)return flag > n2.flag;//入边在出边前        return x < n2.x;    }};vector<Node> line;vector<int> vs;const int maxn = 10005;struct sgt{    int len[maxn<<2];    int cnt[maxn<<2];    int cov[maxn<<2];    int left[maxn<<2];    int right[maxn<<2];    void maintain(int node,int L,int R){        if(cov[node] > 0){            len[node] = vs[R]-vs[L-1];            cnt[node] = 1;            left[node] = right[node] = 1;        } else {            if(L == R){                len[node] = 0;                cnt[node] = 0;                left[node] = right[node] = 0;            }else{                CHD;                len[node] = len[lc]+len[rc];                cnt[node] = cnt[lc]+cnt[rc]-(left[rc]&right[lc]);                left[node] = left[lc];                right[node] = right[rc];            }        }    }    void update(int from,int to,int val,int node,int L,int R){        if(from <= L && R <= to){            cov[node] += val;        } else {            MID;CHD;            if(from <= mid) update(from,to,val,lc,L,mid);            else    maintain(lc,L,mid);            if(to > mid) update(from,to,val,rc,mid+1,R);            else    maintain(rc,mid+1,R);        }        maintain(node,L,R);    }    int solve(){        int ans = 0,ans2 = 0;//竖直和水平方向的周长        int n = vs.size()-1;        int last = 0;        rep(i,0,line.size()-1){            int x = line[i].x;            int f = line[i].y1+1;            int t = line[i].y2;            if(i > 0){                int tmp = cnt[1] * (x-line[i-1].x);                ans2 += tmp*2;            }            update(f,t,line[i].flag,1,1,n);            ans += abs(last-len[1]);//竖直方向长度变化            last = len[1];        }        return ans+ans2;    }}tree;void pre(){    sort(vs.begin(),vs.end());    vs.erase(unique(vs.begin(),vs.end()),vs.end());    rep(i,0,line.size()-1){        line[i].y1 = lower_bound(vs.begin(),vs.end(),line[i].y1) - vs.begin();        line[i].y2 = lower_bound(vs.begin(),vs.end(),line[i].y2) - vs.begin();    }    sort(line.begin(),line.end());}int main(){    int n;    scanf("%d",&n);    if(n == 0){        printf("0\n");        return 0;    }    line.reserve(n<<1);    vs.reserve(n<<1);    rep(i,1,n){        int x1,y1,x2,y2;        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);        vs.push_back(y1);        vs.push_back(y2);        line.push_back(Node(x1,y1,y2,1));        line.push_back(Node(x2,y1,y2,-1));    }    pre();    int ans = tree.solve();    printf("%d\n",ans);    return 0;}
0 0
原创粉丝点击