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

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

const int INF = 1e9;

const int MAXN = 1e6;
//将题目的[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;
    }
}

//ok
int qtop;

struct Query {
    int t, op, x, y, ans;
    bool operator<(const Query &q)const {
        return x < q.x;
    }
} q[MAXN + 5], tq[MAXN + 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)
            //更新tq[j].y点的值为INF
            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);
        //只是左上角象限,同x全部先询问,然后再修改,消除同x的影响,其次询问的y是不包含自身的
        //实际上,这道题不是计数,不是特别影响
        for(int j = i; j < nxt; ++j) {
            if(tq[j].op == 2)
                //[tq[i].y+1,H]的答案
                tq[j].ans = min(tq[i].ans, (tq[j].x - tq[j].y) + query(1, 1, H, tq[j].y + 1, H));
        }
        for(int j = i; j < nxt; ++j) {
            if(tq[j].op == 1)
                //更新tq[j].y点的值为负的tq[j].x+tq[j].y,这样取最大值的时候就变成原数的最小值
                update(1, 1, H, tq[j].y, (-tq[j].x + tq[j].y));
        }
    }
    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);
        //左下角象限,包含x负半轴和y负半轴,同x全部先修改,然后再询问
        //实际上,这道题不是计数,不是特别影响
        for(int j = i; j < nxt; ++j) {
            if(tq[j].op == 1)
                //更新tq[j].y点的值为tq[j].x+tq[j].y
                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)
                //[1,tq[i].y]的答案
                tq[j].ans = min(tq[i].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);
        //右上角象限,包含x正半轴和y正半轴,同x全部先修改,然后再询问
        //实际上,这道题不是计数,不是特别影响
        for(int j = i; j > nxt; --j) {
            if(tq[j].op == 1)
                //更新tq[j].y点的值为负的tq[j].x+tq[j].y
                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)
                //[1,tq[i].y]的最大值
                tq[j].ans = min(tq[i].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);
        //右上角象限,包含x正半轴和y正半轴,同x全部先询问,然后再修改,并且询问的不含同y的
        //实际上,这道题不是计数,不是特别影响
        for(int j = i; j > nxt; --j) {
            if(tq[j].op == 2)
                //[1,tq[i].y]的最大值
                tq[j].ans = min(tq[i].ans, (-tq[j].x + tq[j].y) + query(1, 1, H, 1, tq[j].y - 1));
        }
        for(int j = i; j > nxt; --j) {
            if(tq[j].op == 1)
                //更新tq[j].y点的值为tq[j].x+tq[j].y
                update(1, 1, H, tq[j].y, (tq[j].x - 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);
//    printf("After solveUL(%d,%d):\n",l,r);
//    for(int i = 1; i <= qtop; ++i) {
//        if(q[i].op == 2) {
//            printf(" Query %d: %d\n",q[i].t, q[i].ans);
//        }
//    }
//    printf("\n");
    calc_downleft(tqtop);
//    printf("After solveDL(%d,%d):\n",l,r);
//    for(int i = 1; i <= qtop; ++i) {
//        if(q[i].op == 2) {
//            printf(" Query %d: %d\n",q[i].t, q[i].ans);
//        }
//    }
//    printf("\n");
    calc_upright(tqtop);
//    printf("After solveUR(%d,%d):\n",l,r);
//    for(int i = 1; i <= qtop; ++i) {
//        if(q[i].op == 2) {
//            printf(" Query %d: %d\n",q[i].t, q[i].ans);
//        }
//    }
//    printf("\n");
    calc_downright(tqtop);
//    printf("After solveDR(%d,%d):\n",l,r);
//    for(int i = 1; i <= qtop; ++i) {
//        if(q[i].op == 2) {
//            printf(" Query %d: %d\n",q[i].t, q[i].ans);
//        }
//    }
//    printf("\n");
    return;
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int n, m;
    scanf("%d%d", &n, &m);
    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);
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/Inko/p/11469513.html