1. 程式人生 > >【BZOJ1176】[BOI2007]Mokia 摩基亞

【BZOJ1176】[BOI2007]Mokia 摩基亞

【BZOJ1176】[BOI2007]Mokia 摩基亞

題面

bzoj
洛谷

題解

顯然的\(CDQ\)\(/\)樹套樹題
然而根本不想寫樹套樹,那就用\(CDQ\)吧。。。
考慮到點\((x1,y1)\)\((x2,y2)\)區域內既有上限又有下限我們不是很好算
於是將這個區域的貢獻寫成另外一種形式,
\((x,y)\)\((0,0)\)之間區域的貢獻為\(S_{(x,y)}\),則上面的貢獻可表示為
\(S_{(x2,y2)}-S_{(x2,y1-1)}-S_{(y2,x1-1)}+S_{(x1-1,y1-1)}\)
分別統計四個貢獻就很容易辣
程式碼

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
namespace IO { 
    const int BUFSIZE = 1 << 20; 
    char ibuf[BUFSIZE], *is = ibuf, *it = ibuf; 
    inline char gc() { 
        if (is == it) it = (is = ibuf) + fread(ibuf, 1, BUFSIZE, stdin); 
        return *is++; 
    } 
} 
inline int gi() {
    register int data = 0, w = 1;
    register char ch = 0;
    while (ch != '-' && (ch > '9' || ch < '0')) ch = IO::gc();
    if (ch == '-') w = -1 , ch = IO::gc();
    while (ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = IO::gc();
    return w * data;
} 
#define MAX_N 200005 
#define MAX_W 2000005 
struct Node { int x, y, id, w; } t[MAX_N << 2]; int ans[MAX_N]; 
bool cmp_x(Node a, Node b) { return (a.x == b.x) ? (a.y < b.y) : (a.x < b.x); } 

int N, c[MAX_W]; 
inline int lb(int x) { return x & -x; } 
void add(int x, int v) { while (x <= N) c[x] += v, x += lb(x); } 
int sum(int x) { int res = 0; while (x > 0) res += c[x], x -= lb(x); return res; } 
void Div(int l, int r) { 
    if (l == r) return ; 
    int mid = (l + r) >> 1; 
    Div(l, mid); Div(mid + 1, r); 
    int j = l; 
    for (int i = mid + 1; i <= r; i++) { 
        if (t[i].id == 0) continue; 
        for (; t[j].x <= t[i].x && j <= mid; ++j) if (t[j].id == 0) add(t[j].y, t[j].w); 
        ans[t[i].id] += sum(t[i].y) * t[i].w; 
    } 
    for (int i = l; i < j; i++) if (t[i].id == 0) add(t[i].y, -t[i].w); 
    inplace_merge(&t[l], &t[mid + 1], &t[r + 1], cmp_x); 
} 
int main () { 
    gi(); N = gi(); int tot = 0, cnt = 0; 
    for (;;) { 
        int op = gi(); if (op == 3) break; 
        int x = gi(), y = gi(); 
        if (op == 1) t[++tot] = (Node){x, y, 0, gi()}; 
        else { 
            int _x = gi(), _y = gi(); ++cnt; 
            t[++tot] = (Node){_x, _y, cnt, 1}; 
            t[++tot] = (Node){_x, y - 1, cnt, -1}; 
            t[++tot] = (Node){x - 1, _y, cnt, -1}; 
            t[++tot] = (Node){x - 1, y - 1, cnt, 1}; 
        } 
    } 
    Div(1, tot); 
    for (int i = 1; i <= cnt; i++) printf("%d\n", ans[i]); 
    return 0; 
}