1. 程式人生 > >HDU3265 掃描線+線段樹 區間並

HDU3265 掃描線+線段樹 區間並

題意:N個海報,每個海報中間有個矩形的洞。問這N個海報覆蓋面積和是多少。

分析: 非常經典的題目了,掃描線+線段樹 進行 區間並操作 

既然海報內有塊矩形不能計算入內,只要把海報分為四塊不重疊的部分就好了。

重點是空間限制比較緊,交了若干次才A的。。改用unsigned short(0...65536) 儲存座標才A了。。

注意:若掃描線個數小於2直接輸出0,如果按常規的線段樹求區間和會返回RE。。

截圖紀念一下這個讓我除錯了N久bug的題目。。


程式碼如下:

#include <cstdio>
#include <algorithm>
using namespace std;

const int maxn = 4e5+10;
struct Line{
   unsigned short x,y1,y2;
   bool f;
   bool operator <(const Line &rhs) const {
      return x<rhs.x;
   }
}line[maxn];
int y[maxn];
int n,tot;

inline void addLine(int a, int b,int c, int d) {
   tot++;
   line[tot].x = a; line[tot].y1 = b; line[tot].y2 = d;
   line[tot].f = 1; y[tot] = b;
   tot++;
   line[tot].x = c; line[tot].y1 = b; line[tot].y2 = d;
   line[tot].f = 0; y[tot] = d;
}

struct node{
    int l,r;
    int c,len;
    int lf,rf;
};

struct Tree{
     node tr[maxn*4];
     #define lch(u) (u<<1)
     #define rch(u) (u<<1|1)
     #define Mid (tr[u].l+tr[u].r)>>1

     void build(int u, int a, int b) {
         tr[u].l = a; tr[u].r = b;
         tr[u].lf = y[a]; tr[u].rf = y[b];
         tr[u].c = tr[u].len = 0;
         if (a+1 == b) return ;
         build(lch(u),a,Mid);
         build(rch(u),Mid,b);
     }

    inline void cal(int u){
         if (tr[u].c > 0) {
             tr[u].len = tr[u].rf - tr[u].lf;
         }
         else {
            if (tr[u].l+1 == tr[u].r) tr[u].len = 0;
            else tr[u].len = tr[lch(u)].len + tr[rch(u)].len;
         }
     }

     void update(int u, Line e){
         if (e.y1 == tr[u].lf && e.y2 == tr[u].rf) {
            if (e.f == 1) tr[u].c++; else tr[u].c--;
            cal(u);
            return ;
         }
         if (e.y2 <= tr[lch(u)].rf) update(lch(u),e);
         else if (e.y1 >= tr[rch(u)].lf) update(rch(u),e);
         else {
            Line tmp = e;
            tmp.y2 = tr[lch(u)].rf;
            update(lch(u),tmp);

            tmp = e;
            tmp.y1 = tr[rch(u)].lf;
            update(rch(u),tmp);
         }
         cal(u);
     }
}T;

int x[10];

int main(){
    while (scanf("%d",&n)==1 && n){
        tot = 0;
        for (int i=1; i<=n; i++) {
            for (int j=1; j<=8; j++) scanf("%d",&x[j]);
            if (x[1]<x[5] && x[2]<x[4]) addLine(x[1],x[2],x[5],x[4]);
            if (x[7]<x[3] && x[2]<x[4]) addLine(x[7],x[2],x[3],x[4]);
            if (x[5]<x[7] && x[8]<x[4]) addLine(x[5],x[8],x[7],x[4]);
            if (x[5]<x[7] && x[2]<x[6]) addLine(x[5],x[2],x[7],x[6]);
        }
        sort(line+1,line+tot+1);
        sort(y+1,y+tot+1);

        if (tot<2) {
            printf("0\n");
            continue;
        }

        T.build(1,1,tot);
        T.update(1,line[1]);

        unsigned int ans = 0;
        for (int i=2; i<=tot; i++) {
            ans += T.tr[1].len*(line[i].x-line[i-1].x);
            T.update(1,line[i]);
        }
        printf("%u\n",ans);
    }
    return 0;
}