下面是一种正确的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分治。