zoukankan      html  css  js  c++  java
  • AcWing

    下面是一种正确的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
    ", 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 == '
    ' || c == '
    ' || c == '	';
        }
    
        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('
    ');
        }
    
        template<class T> inline void Write2(T &x) {
            if(x < 0) {
                putchar('-');
                PutChar(-x);
            } else
                PutChar(x);
            putchar('
    ');
        }
    }
    
    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
    ", 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 == '
    ' || c == '
    ' || c == '	';
        }
    
        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('
    ');
        }
    
        template<class T> inline void Write2(T &x) {
            if(x < 0) {
                putchar('-');
                PutChar(-x);
            } else
                PutChar(x);
            putchar('
    ');
        }
    }
    
    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分治。

  • 相关阅读:
    053705
    053704
    053703
    053702
    053701
    053700
    053699
    053698
    053697
    HDU 3746 Cyclic Nacklace
  • 原文地址:https://www.cnblogs.com/Inko/p/11469513.html
Copyright © 2011-2022 走看看