AcWing - 254 - 天使玩偶 = CDQ分治

下面是一种正确的CDQ分治,使用线段树来实现,渐进复杂度到达要求。但是貌似CDQ分治在解决偏序问题的时候要尽可能使用树状数组。小心不要把i和j写反了。下面这个写法虽然没有WA,但是TLE了,这个非常麻烦。事实上是因为有很多多余的操作影响了常数,比如多余的排序、没有用的修改、询问。当然这个线段树也可以换成几倍快的树状数组。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int INF = 1e9;
//将题目的[0,1e6]偏移到[1,1e6+1]
const int H = 1e6 + 1;

int st[H * 4 + 5];
inline void push_up(int o) {
    st[o] = min(st[o << 1], st[o << 1 | 1]);
}

void build(int o, int l, int r) {
    if(l == r) {
        st[o] = INF;
    } else {
        int mid = (l + r) >> 1;
        build(o << 1, l, mid);
        build(o << 1 | 1, mid + 1, r);
        push_up(o);
    }
}

void update(int o, int l, int r, int x, int v) {
    if(l == r) {
        st[o] = min(st[o], v);
    } else {
        int mid = (l + r) >> 1;
        if(x <= mid)
            update(o << 1, l, mid, x, v);
        else
            update(o << 1 | 1, mid + 1, r, x, v);
        push_up(o);
    }
}

void unupdate(int o, int l, int r, int x) {
    if(l == r) {
        st[o] = INF;
    } else {
        int mid = (l + r) >> 1;
        if(x <= mid)
            unupdate(o << 1, l, mid, x);
        else
            unupdate(o << 1 | 1, mid + 1, r, x);
        push_up(o);
    }
}

int query(int o, int l, int r, int ql, int qr) {
    if(ql <= l && r <= qr) {
        return st[o];
    } else {
        int mid = (l + r) >> 1, res = INF;
        if(ql <= mid)
            res = min(res, query(o << 1, l, mid, ql, qr));
        if(qr >= mid + 1)
            res = min(res, query(o << 1 | 1, mid + 1, r, ql, qr));
        return res;
    }
}

const int MAXNM = 1e6;

struct Query {
    int t, op, x, y, ans;
    bool operator<(const Query &q)const {
        return x < q.x;
    }
} q[MAXNM + 5], tq[MAXNM + 5];

inline int before_calc(int l, int r) {
    int tqtop = 0, mid = (l + r) >> 1;
    for(int i = l; i <= mid; ++i) {
        if(q[i].op == 1)
            tq[++tqtop] = q[i];
    }
    for(int i = mid + 1; i <= r; ++i) {
        if(q[i].op == 2)
            tq[++tqtop] = q[i];
    }
    sort(tq + 1, tq + 1 + tqtop);
    return tqtop;
}

inline void after_calc(int tqtop) {
    for(int i = 1; i <= tqtop; ++i) {
        if(tq[i].op == 1)
            unupdate(1, 1, H, tq[i].y);
        else
            q[tq[i].t].ans = tq[i].ans;
    }
}

int calc_upleft(int tqtop) {
    for(int i = 1, nxt; i <= tqtop; i = nxt) {
        for(nxt = i + 1; nxt <= tqtop && tq[i].x == tq[nxt].x; ++nxt);
        for(int j = i; j < nxt; ++j) {
            if(tq[j].op == 1)
                update(1, 1, H, tq[j].y, (-tq[j].x + tq[j].y));
        }
        for(int j = i; j < nxt; ++j) {
            if(tq[j].op == 2)
                tq[j].ans = min(tq[j].ans, (tq[j].x - tq[j].y) + query(1, 1, H, tq[j].y, H));
        }
    }
    after_calc(tqtop);
}

int calc_downleft(int tqtop) {
    for(int i = 1, nxt; i <= tqtop; i = nxt) {
        for(nxt = i + 1; nxt <= tqtop && tq[i].x == tq[nxt].x; ++nxt);
        for(int j = i; j < nxt; ++j) {
            if(tq[j].op == 1)
                update(1, 1, H, tq[j].y, (-tq[j].x - tq[j].y));
        }
        for(int j = i; j < nxt; ++j) {
            if(tq[j].op == 2)
                tq[j].ans = min(tq[j].ans, (tq[j].x + tq[j].y) + query(1, 1, H, 1, tq[j].y));
        }
    }
    after_calc(tqtop);
}

int calc_upright(int tqtop) {
    for(int i = tqtop, nxt; i >= 1; i = nxt) {
        for(nxt = i - 1; nxt >= 1 && tq[i].x == tq[nxt].x; --nxt);
        for(int j = i; j > nxt; --j) {
            if(tq[j].op == 1)
                update(1, 1, H, tq[j].y, (tq[j].x + tq[j].y));
        }
        for(int j = i; j > nxt; --j) {
            if(tq[j].op == 2)
                tq[j].ans = min(tq[j].ans, (-tq[j].x - tq[j].y) + query(1, 1, H, tq[j].y, H));
        }
    }
    after_calc(tqtop);
}

int calc_downright(int tqtop) {
    for(int i = tqtop, nxt; i >= 1; i = nxt) {
        for(nxt = i - 1; nxt >= 1 && tq[i].x == tq[nxt].x; --nxt);
        for(int j = i; j > nxt; --j) {
            if(tq[j].op == 1)
                update(1, 1, H, tq[j].y, (tq[j].x - tq[j].y));
        }
        for(int j = i; j > nxt; --j) {
            if(tq[j].op == 2)
                tq[j].ans = min(tq[j].ans, (-tq[j].x + tq[j].y) + query(1, 1, H, 1, tq[j].y));
        }
    }
    after_calc(tqtop);
}

void solve(int l, int r) {
    if(l == r)
        return;
    int mid = (l + r) >> 1;
    solve(l, mid);
    solve(mid + 1, r);

    //这里是没必要每一层都排序的,事实上是每一层直接归并就可以了
    int tqtop = before_calc(l, r);
    calc_upleft(tqtop);
    calc_downleft(tqtop);
    calc_upright(tqtop);
    calc_downright(tqtop);
    return;
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int n, m;
    scanf("%d%d", &n, &m);
    int qtop = 0;
    for(int i = 1; i <= n; ++i) {
        int x, y;
        scanf("%d%d", &x, &y);
        ++qtop;
        q[qtop].op = 1;
        q[qtop].t = qtop;
        q[qtop].x = x + 1;
        q[qtop].y = y + 1;
        q[qtop].ans = INF;
    }
    for(int i = 1; i <= m; ++i) {
        int op, x, y;
        scanf("%d%d%d", &op, &x, &y);
        ++qtop;
        q[qtop].op = op;
        q[qtop].t = qtop;
        q[qtop].x = x + 1;
        q[qtop].y = y + 1;
        q[qtop].ans = INF;
    }
    build(1, 1, H);
    solve(1, qtop);
    for(int i = 1; i <= qtop; ++i) {
        if(q[i].op == 2) {
            printf("%d\n", q[i].ans);
        }
    }
}

加上快读,换成树状数组,树状数组修改时跳过不可能更新到当前询问的修改,换成归并排序,然后CDQ剪枝(某分支的操作类型全部是修改操作时,该分支没有任何询问会被更新,直接按x排序并返回该分支)。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

namespace FastIO {
#define BUF_SIZE 1000000
    bool IOError = 0;
    inline char NextChar() {
        static char buf[BUF_SIZE], *pl = buf + BUF_SIZE, *pr = buf + BUF_SIZE;
        if(pl == pr) {
            pl = buf, pr = buf + fread(buf, 1, BUF_SIZE, stdin);
            if(pr == pl) {
                IOError = 1;
                return -1;
            }
        }
        return *pl++;
    }
#undef BUF_SIZE

    inline bool Blank(char c) {
        return c == ' ' || c == '\n' || c == '\r' || c == '\t';
    }

    template<class T> inline void Read(T &x) {
        char c;
        while(Blank(c = NextChar()));
        if(!IOError) {
            for(x = 0; '0' <= c && c <= '9'; c = NextChar())
                x = (x << 3) + (x << 1) + c - '0';
        }
    }

    template<class T> inline void Read2(T &x) {
        char c;
        bool f = 0;
        while(Blank(c = NextChar()));
        if(!IOError) {
            if(c == '-') {
                f = 1;
                c = NextChar();
            }
            for(x = 0; '0' <= c && c <= '9'; c = NextChar())
                x = (x << 3) + (x << 1) + c - '0';
        }
        if(f)
            x = -x;
    }

    template<class T> inline void PutChar(T x) {
        if(x > 9)
            PutChar(x / 10);
        putchar(x % 10 + '0');
    }

    template<class T> inline void Write(T &x) {
        PutChar(x);
        putchar('\n');
    }

    template<class T> inline void Write2(T &x) {
        if(x < 0) {
            putchar('-');
            PutChar(-x);
        } else
            PutChar(x);
        putchar('\n');
    }
}

using namespace FastIO;

const int INF = 1e9;
//将题目的[0,1e6]偏移到[1,1e6+1]
const int H = 1e6 + 1;

int bit[H + 5];

void build() {
    for(int i = 1; i <= H; ++i)
        bit[i] = INF;
}

void update(int x, int v) {
    for(; x <= H; x += x & -x)
        bit[x] = min(bit[x], v);
}

void unupdate(int x) {
    for(; x <= H; x += x & -x)
        bit[x] = INF;
}

int query(int x) {
    int res = INF;
    for(; x >= 1; x -= x & -x)
        res = min(res, bit[x]);
    return res;
}

const int MAXNM = 1e6;

struct Query {
    int t, op, x, y, ans;
    bool operator<(const Query &q)const {
        return x < q.x;
    }
} q[MAXNM + 5], tq[MAXNM + 5], tq2[MAXNM + 5];

bool cmp(const Query &q1, const Query &q2) {
    return q1.t < q2.t;
}

inline int before_calc(int l, int r) {
    int mid = (l + r) >> 1;
    int tqtop = 0;
    for(int i = l; i <= mid; ++i) {
        if(q[i].op == 1) {
            tq[++tqtop] = q[i];
            tq[tqtop].t = i;
        }
    }
    int l1 = tqtop;
    for(int i = mid + 1; i <= r; ++i) {
        if(q[i].op == 2) {
            tq[++tqtop] = q[i];
            tq[tqtop].t = i;
        }
    }
    int l2 = tqtop;

    merge(tq + 1, tq + 1 + l1, tq + 1 + l1, tq + 1 + l2, tq2 + 1);
    for(int j = 1; j <= l2; ++j) {
        tq[j] = tq2[j];
    }
    return l2;
}

inline void after_calc(int l, int r, int tqtop) {
    for(int i = 1; i <= tqtop; ++i) {
        if(tq[i].op == 2)
            q[tq[i].t].ans = tq[i].ans;
    }
    int mid = (l + r) >> 1;
    merge(q + l, q + mid + 1, q + mid + 1, q + r + 1, tq2 + 1);
    for(int j = l; j <= r; ++j) {
        q[j] = tq2[j - l + 1];
    }
}

int calc_upleft(int tqtop) {
    int maxy = -INF;
    for(int i = 1; i <= tqtop; ++i) {
        if(tq[i].op == 2)
            maxy = max(maxy, H - tq[i].y + 1);
    }
    if(maxy != INF) {
        for(int i = 1, nxt; i <= tqtop; i = nxt) {
            for(nxt = i + 1; nxt <= tqtop && tq[i].x == tq[nxt].x; ++nxt);
            for(int j = i; j < nxt; ++j) {
                if(tq[j].op == 1 && H - tq[j].y + 1 <= maxy)
                    update(H - tq[j].y + 1, (-tq[j].x + tq[j].y));
            }
            for(int j = i; j < nxt; ++j) {
                if(tq[j].op == 2)
                    tq[j].ans = min(tq[j].ans, (tq[j].x - tq[j].y) + query(H - tq[j].y + 1));
            }
        }
        for(int i = 1; i <= tqtop; ++i) {
            if(tq[i].op == 1 && H - tq[i].y + 1 <= maxy)
                unupdate(H - tq[i].y + 1);
        }
    }
}

int calc_downleft(int tqtop) {
    int maxy = -INF;
    for(int i = 1; i <= tqtop; ++i) {
        if(tq[i].op == 2)
            maxy = max(maxy, tq[i].y);
    }
    if(maxy != INF) {
        for(int i = 1, nxt; i <= tqtop; i = nxt) {
            for(nxt = i + 1; nxt <= tqtop && tq[i].x == tq[nxt].x; ++nxt);
            for(int j = i; j < nxt; ++j) {
                if(tq[j].op == 1 && tq[j].y <= maxy)
                    update(tq[j].y, (-tq[j].x - tq[j].y));
            }
            for(int j = i; j < nxt; ++j) {
                if(tq[j].op == 2)
                    tq[j].ans = min(tq[j].ans, (tq[j].x + tq[j].y) + query(tq[j].y));
            }
        }
        for(int i = 1; i <= tqtop; ++i) {
            if(tq[i].op == 1 && tq[i].y <= maxy)
                unupdate(tq[i].y);
        }
    }
}

int calc_upright(int tqtop) {
    int maxy = -INF;
    for(int i = 1; i <= tqtop; ++i) {
        if(tq[i].op == 2)
            maxy = max(maxy, H - tq[i].y + 1);
    }
    if(maxy != INF) {
        for(int i = tqtop, nxt; i >= 1; i = nxt) {
            for(nxt = i - 1; nxt >= 1 && tq[i].x == tq[nxt].x; --nxt);
            for(int j = i; j > nxt; --j) {
                if(tq[j].op == 1 && H - tq[j].y + 1 <= maxy)
                    update(H - tq[j].y + 1, (tq[j].x + tq[j].y));
            }
            for(int j = i; j > nxt; --j) {
                if(tq[j].op == 2)
                    tq[j].ans = min(tq[j].ans, (-tq[j].x - tq[j].y) + query(H - tq[j].y + 1));
            }
        }
        for(int i = 1; i <= tqtop; ++i) {
            if(tq[i].op == 1 && H - tq[i].y + 1 <= maxy)
                unupdate(H - tq[i].y + 1);
        }
    }
}

int calc_downright(int tqtop) {
    int maxy = -INF;
    for(int i = 1; i <= tqtop; ++i) {
        if(tq[i].op == 2)
            maxy = max(maxy, tq[i].y);
    }
    if(maxy != INF) {
        for(int i = tqtop, nxt; i >= 1; i = nxt) {
            for(nxt = i - 1; nxt >= 1 && tq[i].x == tq[nxt].x; --nxt);
            for(int j = i; j > nxt; --j) {
                if(tq[j].op == 1 && tq[j].y <= maxy)
                    update(tq[j].y, (tq[j].x - tq[j].y));
            }
            for(int j = i; j > nxt; --j) {
                if(tq[j].op == 2)
                    tq[j].ans = min(tq[j].ans, (-tq[j].x + tq[j].y) + query(tq[j].y));
            }
        }
        for(int i = 1; i <= tqtop; ++i) {
            if(tq[i].op == 1 && tq[i].y <= maxy)
                unupdate(tq[i].y);
        }
    }
}

void solve(int l, int r) {

    if(l == r)
        return;
    int mid = (l + r) >> 1;
    bool allupdate = true;
    for(int i = l; i <= mid; i++) {
        if(q[i].op == 2) {
            allupdate = false;
            break;
        }
    }
    if(!allupdate)
        solve(l, mid);
    else
        sort(q + l, q + 1 + mid);
    bool allupdate2 = true;
    for(int i = mid + 1; i <= r; i++) {
        if(q[i].op == 2) {
            allupdate2 = false;
            break;
        }
    }
    if(!allupdate2)
        solve(mid + 1, r);
    else
        sort(q + mid + 1, q + 1 + r);

    if(allupdate && allupdate2)
        return;
    //这里是没必要每一层都排序的,事实上是每一层直接归并就可以了
    int tqtop = before_calc(l, r);
    calc_upleft(tqtop);
    calc_downleft(tqtop);
    calc_upright(tqtop);
    calc_downright(tqtop);
    after_calc(l, r, tqtop);
    return;
}


int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int n, m;
    Read(n), Read(m);
    //scanf("%d%d", &n, &m);
    int qtop = 0;
    for(int i = 1; i <= n; ++i) {
        int x, y;
        Read(x), Read(y);
        //scanf("%d%d", &x, &y);
        ++qtop;
        q[qtop].op = 1;
        q[qtop].t = qtop;
        q[qtop].x = x + 1;
        q[qtop].y = y + 1;
        q[qtop].ans = INF;
    }
    for(int i = 1; i <= m; ++i) {
        int op, x, y;
        Read(op), Read(x), Read(y);
        //scanf("%d%d%d", &op, &x, &y);
        ++qtop;
        q[qtop].op = op;
        q[qtop].t = qtop;
        q[qtop].x = x + 1;
        q[qtop].y = y + 1;
        q[qtop].ans = INF;
    }
    build();
    solve(1, qtop);
    sort(q + 1, q + 1 + qtop, cmp);
    for(int i = 1; i <= qtop; ++i) {
        if(q[i].op == 2) {
            Write(q[i].ans);
            //printf("%d\n", q[i].ans);
        }
    }
}

AcWing上面还对空间作出要求,把ans项剥离出去,然后把t和op两个整数合成一个,算一下貌似原来刚好够64MB。原本是:20+20+20+4,改了之后是12+12+12+4+4,是绰绰有余。然后把CDQ剪枝换了一下位置,应该再加上一层常数优化的,就是第一层不检测剪枝直接递归下去,也不进行最后一次归并。然后,还可以统计实际上插入树状数组中的数的个数,当插入的数过多时不进行撤销树状数组,直接整棵重建(毕竟memset比一堆判断、与、加减、赋值的树状数组快得多)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

namespace FastIO {
#define BUF_SIZE 1000000
    bool IOError = 0;
    inline char NextChar() {
        static char buf[BUF_SIZE], *pl = buf + BUF_SIZE, *pr = buf + BUF_SIZE;
        if(pl == pr) {
            pl = buf, pr = buf + fread(buf, 1, BUF_SIZE, stdin);
            if(pr == pl) {
                IOError = 1;
                return -1;
            }
        }
        return *pl++;
    }
#undef BUF_SIZE

    inline bool Blank(char c) {
        return c == ' ' || c == '\n' || c == '\r' || c == '\t';
    }

    template<class T> inline void Read(T &x) {
        char c;
        while(Blank(c = NextChar()));
        if(!IOError) {
            for(x = 0; '0' <= c && c <= '9'; c = NextChar())
                x = (x << 3) + (x << 1) + c - '0';
        }
    }

    template<class T> inline void Read2(T &x) {
        char c;
        bool f = 0;
        while(Blank(c = NextChar()));
        if(!IOError) {
            if(c == '-') {
                f = 1;
                c = NextChar();
            }
            for(x = 0; '0' <= c && c <= '9'; c = NextChar())
                x = (x << 3) + (x << 1) + c - '0';
        }
        if(f)
            x = -x;
    }

    template<class T> inline void PutChar(T x) {
        if(x > 9)
            PutChar(x / 10);
        putchar(x % 10 + '0');
    }

    template<class T> inline void Write(T &x) {
        PutChar(x);
        putchar('\n');
    }

    template<class T> inline void Write2(T &x) {
        if(x < 0) {
            putchar('-');
            PutChar(-x);
        } else
            PutChar(x);
        putchar('\n');
    }
}

using namespace FastIO;

const int INF = 0x3f3f3f3f;
//将题目的[0,1e6]偏移到[1,1e6+1]
const int H = 1e6 + 1;

int bit[H + 5];

inline void build() {
    memset(bit, INF, sizeof(bit));
}

void update(int x, int v) {
    for(; x <= H; x += x & -x) {
        if(v < bit[x])
            bit[x] = v;
    }
}

void unupdate(int x) {
    for(; x <= H; x += x & -x)
        bit[x] = INF;
}

int query(int x) {
    int res = INF;
    for(; x >= 1; x -= x & -x) {
        if(bit[x] < res)
            res = bit[x];
    }
    return res;
}

const int MAXNM = 1e6;

struct Query {
    int op, x, y;
    bool operator<(const Query &q)const {
        return x < q.x;
    }
} q[MAXNM + 5], tq[MAXNM + 5], tq2[MAXNM + 5];

inline int before_calc(int l, int r) {
    int mid = (l + r) >> 1;
    int tqtop = 0;
    for(int i = l; i <= mid; ++i) {
        if(q[i].op & 1)
            tq[++tqtop] = q[i];
    }
    int l1 = tqtop;
    for(int i = mid + 1; i <= r; ++i) {
        if(!(q[i].op & 1))
            tq[++tqtop] = q[i];
    }
    int l2 = tqtop;

    merge(tq + 1, tq + 1 + l1, tq + 1 + l1, tq + 1 + l2, tq2 + 1);
    for(int j = 1; j <= l2; ++j)
        tq[j] = tq2[j];
    return l2;
}

inline void after_calc(int l, int r, int tqtop) {
    int mid = (l + r) >> 1;
    merge(q + l, q + mid + 1, q + mid + 1, q + r + 1, tq2 + 1);
    for(int j = l; j <= r; ++j)
        q[j] = tq2[j - l + 1];
}

int ans[MAXNM + 5];

//超过该界时不进行取消树状数组,直接重建,因为树状数组有很多加法、判断之类的,而memset快得多
const int BUILDLIMIT = 5e4;

int calc_upleft(int tqtop) {
    int maxy = -INF;
    for(int i = 1; i <= tqtop; ++i) {
        if(!(tq[i].op & 1))
            maxy = max(maxy, H - tq[i].y + 1);
    }
    if(maxy != INF) {
        int cnt = 0;
        for(int i = 1, nxt; i <= tqtop; i = nxt) {
            for(nxt = i + 1; nxt <= tqtop && tq[i].x == tq[nxt].x; ++nxt);
            for(int j = i; j < nxt; ++j) {
                if(tq[j].op & 1 && H - tq[j].y + 1 <= maxy) {
                    update(H - tq[j].y + 1, (-tq[j].x + tq[j].y));
                    ++cnt;
                }
            }
            for(int j = i; j < nxt; ++j) {
                if(!(tq[j].op & 1))
                    ans[tq[j].op >> 1] = min(ans[tq[j].op >> 1], (tq[j].x - tq[j].y) + query(H - tq[j].y + 1));

            }
        }
        if(cnt < BUILDLIMIT) {
            for(int i = 1; i <= tqtop; ++i) {
                if(tq[i].op & 1 && H - tq[i].y + 1 <= maxy)
                    unupdate(H - tq[i].y + 1);
            }
        } else
            build();
    }
}

int calc_downleft(int tqtop) {
    int maxy = -INF;
    for(int i = 1; i <= tqtop; ++i) {
        if(!(tq[i].op & 1))
            maxy = max(maxy, tq[i].y);
    }
    if(maxy != INF) {
        int cnt = 0;
        for(int i = 1, nxt; i <= tqtop; i = nxt) {
            for(nxt = i + 1; nxt <= tqtop && tq[i].x == tq[nxt].x; ++nxt);
            for(int j = i; j < nxt; ++j) {
                if(tq[j].op & 1 && tq[j].y <= maxy) {
                    update(tq[j].y, (-tq[j].x - tq[j].y));
                    ++cnt;
                }
            }
            for(int j = i; j < nxt; ++j) {
                if(!(tq[j].op & 1))
                    ans[tq[j].op >> 1] = min(ans[tq[j].op >> 1], (tq[j].x + tq[j].y) + query(tq[j].y));
            }
        }
        if(cnt < BUILDLIMIT) {
            for(int i = 1; i <= tqtop; ++i) {
                if(tq[i].op & 1 && tq[i].y <= maxy)
                    unupdate(tq[i].y);
            }
        } else
            build();
    }
}

int calc_upright(int tqtop) {
    int maxy = -INF;
    for(int i = 1; i <= tqtop; ++i) {
        if(!(tq[i].op & 1))
            maxy = max(maxy, H - tq[i].y + 1);
    }
    if(maxy != INF) {
        int cnt = 0;
        for(int i = tqtop, nxt; i >= 1; i = nxt) {
            for(nxt = i - 1; nxt >= 1 && tq[i].x == tq[nxt].x; --nxt);
            for(int j = i; j > nxt; --j) {
                if(tq[j].op & 1 && H - tq[j].y + 1 <= maxy) {
                    update(H - tq[j].y + 1, (tq[j].x + tq[j].y));
                    ++cnt;
                }
            }
            for(int j = i; j > nxt; --j) {
                if(!(tq[j].op & 1))
                    ans[tq[j].op >> 1] = min(ans[tq[j].op >> 1], (-tq[j].x - tq[j].y) + query(H - tq[j].y + 1));
            }
        }
        if(cnt < BUILDLIMIT) {
            for(int i = 1; i <= tqtop; ++i) {
                if(tq[i].op & 1 && H - tq[i].y + 1 <= maxy)
                    unupdate(H - tq[i].y + 1);
            }
        } else
            build();
    }
}

int calc_downright(int tqtop) {
    int maxy = -INF;
    for(int i = 1; i <= tqtop; ++i) {
        if(!(tq[i].op & 1))
            maxy = max(maxy, tq[i].y);
    }
    if(maxy != INF) {
        int cnt = 0;
        for(int i = tqtop, nxt; i >= 1; i = nxt) {
            for(nxt = i - 1; nxt >= 1 && tq[i].x == tq[nxt].x; --nxt);
            for(int j = i; j > nxt; --j) {
                if(tq[j].op & 1 && tq[j].y <= maxy) {
                    ++cnt;
                    update(tq[j].y, (tq[j].x - tq[j].y));
                }
            }
            for(int j = i; j > nxt; --j) {
                if(!(tq[j].op & 1))
                    ans[tq[j].op >> 1] = min(ans[tq[j].op >> 1], (-tq[j].x + tq[j].y) + query(tq[j].y));
            }
        }
        if(cnt < BUILDLIMIT) {
            for(int i = 1; i <= tqtop; ++i) {
                if(tq[i].op & 1 && tq[i].y <= maxy)
                    unupdate(tq[i].y);
            }
        } else
            build();
    }
}

void solve(int l, int r, bool firstlayer = false) {
    if(l == r)
        return;
    if(!firstlayer) {
        bool all1 = true;
        for(int i = l; i <= r ; i++) {
            if(!(tq[i].op & 1)) {
                all1 = false;
                break;
            }
        }
        if(all1) {
            sort(q + l, q + r + 1);
            return;
        }
    }
    int mid = (l + r) >> 1;
    solve(l, mid);
    solve(mid + 1, r);
    //这里是没必要每一层都排序的,事实上是每一层直接归并就可以了
    int tqtop = before_calc(l, r);
    calc_upleft(tqtop);
    calc_downleft(tqtop);
    calc_upright(tqtop);
    calc_downright(tqtop);
    if(!firstlayer)
        after_calc(l, r, tqtop);
    return;
}


int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int n, m;
    Read(n), Read(m);
    //scanf("%d%d", &n, &m);
    int qtop = 0;
    for(int i = 1; i <= n; ++i) {
        int x, y;
        Read(x), Read(y);
        ++qtop;
        q[qtop].op = qtop << 1 | 1;
        q[qtop].x = x + 1;
        q[qtop].y = y + 1;
    }
    for(int i = 1; i <= m; ++i) {
        int op, x, y;
        Read(op), Read(x), Read(y);
        ++qtop;
        q[qtop].op = (qtop << 1) | (op & 1);
        q[qtop].x = x + 1;
        q[qtop].y = y + 1;
    }
    build();
    memset(ans, INF, sizeof(ans[0]) * (n + m + 1));
    solve(1, qtop, true);
    const int MAXANS = 5e6;
    for(int i = 1; i <= qtop; ++i) {
        if(ans[i] <= MAXANS) {
            Write(ans[i]);
        }
    }
}

需要注意的是文件快读和普通快读在O2的时候会导致这题RE,区域赛小心一点。

发现还有一种渐进复杂度更好的办法,或许可以代替掉全修改剪枝,就是把初始点的n个丢进去树状数组把后面m个点中的询问拉出来更新,四个维度各做一次,然后前面n个点就彻底没用了,只对后面的m个点做CDQ分治。

转载于:https://www.cnblogs.com/Inko/p/11469513.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值