[Uva11983][线段树][扫描线]Weird Advertisement[好题]

May rem R.I.P.

这道题是用以悼念Renat Mullakhanov(rem)的。

题意:

    二维平面上有N (1N30,000) 个矩形,求被至少K个矩形覆盖的区域的面积 (1K10)

题解:

    用扫描线处理一维,另一维离散化之后建立线段树。

(不要随便看代码。不要随便看代码。不要随便看代码。重要的事情说三遍。 )

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

//Global Variables & Definitions
#define MAXN 60060
#define MAXK 13
typedef long long LL;

int __T;
int N, K;

struct Point { 
    int X, Y;

    Point() {}
    Point(int X, int Y) : X(X), Y(Y) {}

    inline void scan() {
        scanf("%d%d", &X, &Y);
    }
} P[MAXN * 2];

struct Line {
    int X;
    int Ya, Yb;
    int V;

    bool operator < (const Line & b) const {
        return X < b.X;
    }

    void Set(int X, int Ya, int Yb, int V) {
        this -> X = X;
        this -> Ya = Ya;
        this -> Yb = Yb;
        this -> V = V;
    }
} L[MAXN * 2];

map<int, int> V;
//End Global Variables & Definitions

//Segment Tree
int T;
int Y[MAXN * 2];

#define MAXT (MAXN << 2)
#define DEFINE_MID int mid = (l + r) >> 1
#define lson (u << 1)
#define rson (u << 1 | 1)

int leaf[MAXT];
int lazy[MAXT];
int sum[MAXT][MAXK];

void PushUp(int u) {
    int l = u << 1, r = u << 1 | 1;
    for(int i = 0;i < MAXK;++i) sum[u][i] = sum[l][i] + sum[r][i];
}

void Calc(int u) {
    if(lazy[u] >= K) {
        for(int i = 0;i < MAXK;++i) sum[u][i] = sum[u][0];
    } else if(lazy[u]) {
        int laz = lazy[u];

        for(int i = 0;i <= laz;++i) sum[u][i] = sum[u][0];

        if(leaf[u]) for(int i = laz + 1;i < MAXK;++i) sum[u][i] = 0;
        else for(int i = laz + 1;i < MAXK;++i) sum[u][i] = sum[lson][i - laz] + sum[rson][i - laz];
    } else {
        if(leaf[u]) for(int i = 1;i < MAXK;++i) sum[u][i] = 0;
        else PushUp(u);
    }
}

void Build(int u, int l, int r) {
    for(int i = 0;i < MAXK;++i) sum[u][i] = 0;
    leaf[u] = lazy[u] = 0;

    if(l == r) { sum[u][0] = Y[l] - Y[l - 1]; leaf[u] = 1; return; }

    DEFINE_MID;
    Build(lson, l, mid);
    Build(rson, mid + 1, r);

    PushUp(u);
}

inline int Query(int K) {
    return sum[1][K];
}

void Update(int u, int l ,int r, int L, int R, int v) {
    if(L <= l && R >= r) {
        lazy[u] += v;
    } else {
        DEFINE_MID;

        if(L <= mid) Update(lson, l, mid, L, R, v);
        if(R > mid) Update(rson, mid + 1, r, L, R, v);
    }

    Calc(u);
}
//End Segment Tree

//Main Structure
inline void ir() {
    scanf("%d%d", &N, &K);

    int f, s;
    for(int i = 0;i < N;++i) {
        f = i << 1; s = f | 1;

        P[f].scan();
        P[s].scan();

        //left close right open
        ++P[s].X;
        ++P[s].Y;

        Y[f] = P[f].Y;
        Y[s] = P[s].Y;
    }

    sort(Y, Y + N * 2);
    T = unique(Y, Y + N * 2) - Y;

    V.clear();
    for(int i = 0;i < T;++i) V[Y[i]] = i;

    Build(1, 1, T - 1);

    /*       */
    for(int i = 0;i < N;++i) {
        f = i << 1; s = f | 1;

        L[f].Set(P[f].X, P[f].Y, P[s].Y, 1);
        L[s].Set(P[s].X, P[f].Y, P[s].Y, -1);
    }

    sort(L, L + N * 2);
}

LL solve() {
    ir();

    int NN = N * 2;
    LL res = 0ll;
    for(int i = 0;i < NN;++i) {
        if(i) res += (LL)(L[i].X - L[i - 1].X) * Query(K);
        Update(1, 1, T - 1, V[L[i].Ya] + 1, V[L[i].Yb], L[i].V);
    }

    return res;
}

inline void g_ir() {
    scanf("%d", &__T);
}

int main() {
    g_ir();

    int kase = 0;
    while(__T--) printf("Case %d: %lld\n", ++kase, solve());    
    return 0;
}

你可能感兴趣的:(OI,-,Data,Structure,UvaOJ,Uva,线段树,扫描线)