hdu1828,掃描線求矩形邊長

這道題利用掃描線求取矩形的周長,不包括重疊部分。可以掃兩次,豎着掃一次,橫着掃一次,掃兩次這個我寫出bug來了,現在也不知道bug在哪兒QAQ,反手一想算了還是去寫掃一次的。
在這裏插入圖片描述
畫圖模擬一下掃描線掃的過程會發現我們橫着的周長就是每加入一條掃描線後線段樹總長的變化,而豎着的則和我們線段樹維護的被覆蓋的區間是幾段有關,設是x段,那麼本次豎着的周長=(下一條掃描線高度 - 這一條掃描線的高度) * x * 2。所以我們要維護加入掃描線後整個區間的長度,和這個長度由幾段組成。
說一下維護這個段數,對於一個區間,我們要知道他有幾段,就要知道它兩個兒子有多少段,並且由於兒子的合併,可能會導致兩段合併成一段,我們每個區間維護兩個值fl,fr表示這個區間的左半部分和有伴部分是否已經被覆蓋,如果左兒子的右部分和右兒子的左部分都被覆蓋(如下)那麼father的段數 = 兒子的段數之和 - 1,中間部分合並了所以段數少1,其他情況 = 兒子的段數之和。最後得出答案就是
在這裏插入圖片描述

#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<cstdio>
#define mod (10007)
#define middle (l+r)>>1
#define SIZE 1000000+5
#define lowbit(x) (x&(-x))
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long ll;
typedef long double ld;
const int inf_max = 0x3f3f3f;
const ll Linf = 9e18;
const int maxn = 2e4 + 5;
const long double E = 2.7182818;
const double eps=0.0001;
using namespace std;
inline int read()
{
    int f=1,res=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { res=res*10+ch-'0' ; ch=getchar(); }
    return f*res;
}
const int up = 100000 + 10;
struct node {
    int l,r,val,h;
    node(){};
    node(int x,int y,int z,int flag) {l = x;r = y;h = z;val = flag;}
}Line[maxn];
struct tnode {
    int flag,segnum,len,fl,fr;
}tree[up << 2];
int n,totx;
bool cmp(node a,node b) {
    return (a.h == b.h ? a.val > b.val : a.h < b.h);
}
void rst() {
    totx = 0;
    memset(tree,0,sizeof(tree));
}
void pushup(int rt,int l,int r) {
    if(tree[rt].flag) { //如果這一整段區間都被覆蓋,那麼就不用管兒子,直接自己更形
        tree[rt].len = r + 1 - l;
        tree[rt].fl = 1; tree[rt].fr = 1; tree[rt].segnum = 1;
    }else {
        tree[rt].len = tree[lson].len + tree[rson].len;
        tree[rt].segnum = tree[rson].segnum + tree[lson].segnum;
        if(tree[lson].fr == 1 && tree[rson].fl == 1) tree[rt].segnum--; //如何左兒子和右兒子中間部分可以合爲一段
        tree[rt].fl = tree[lson].fl;tree[rt].fr = tree[rson].fr;
    }
}
void update(int rt,int l,int r,int ql,int qr,int f) {
    if(ql == l && qr == r) {
        tree[rt].flag += f;
        pushup(rt,l,r);
        return ;
    }
    int mid = middle;
    if(qr <= mid) update(lson,l,mid,ql,qr,f);
    else if(ql > mid) update(rson,mid + 1,r,ql,qr,f);
    else {
        update(lson,l,mid,ql,mid,f);
        update(rson,mid + 1,r,mid + 1,qr,f);
    }
    pushup(rt,l,r);
}
int main()
{
    while(~scanf("%d",&n)) {
        rst();
        for(int i = 1;i <= n; ++i) {
            int x1,y1,x2,y2;
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            x1 += 10005,y1 += 10005,x2 += 10005,y2 += 10005; //省去離散化
            Line[++totx] = node(x1,x2,y1,1);
            Line[++totx] = node(x1,x2,y2,-1);
        }
        sort(Line + 1,Line + 1 + totx,cmp);
        int ans = 0,pre = 0;
        for(int i = 1;i <= totx; ++i) {
            update(1,1,up,Line[i].l,Line[i].r - 1,Line[i].val); //把點換成區間,所以右端點要-1;
            if(i != totx)
                ans += (2 * tree[1].segnum * (Line[i + 1].h - Line[i].h)); //計算豎着的
            ans += abs(pre - tree[1].len);//計算橫着的
            pre = tree[1].len;
        }
        cout<<ans<<endl;
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章