题解 P6349 [PA2011]Kangaroos


此题除了能用kd树,还能用莫队做

这篇题解分析的是kd树做法qwq

分析

考虑某询问\([A, B]\)与某元素\([l, r]\)有交的条件:\(l \leq B 且 r \geq A\)

可以发现是二维偏序,于是我们用kd树就能快速查询与某询问有交的元素集合

考虑直接回答每个询问,发现因为所得元素集合在序列\(a\)上是无序的,难以快速合并答案

怎么办?不会了QAQ

想一想,我们能快速查询与某询问有交的元素集合,反过来,我们也能快速查询与某元素有交的询问集合

这样,对原问题就有另一种解决思路:先将询问离线,然后把各个元素的贡献加给其对应的询问集合,最后回答每一个询问

同样的问题,无序的贡献难以合并,在这种思路中可以轻松解决:按照\(a\)的顺序加贡献即可

具体的贡献合并略

代码坑是下传标记后标记忘清零(没用到的标记也可能要清零啊!awa)

代码

#include 

#define lep(x, l, r) for(int x = (l), _ = (r); x <= _; ++x)
#define rep(x, r, l) for(int x = (r), _ = (l); x >= _; --x)

using namespace std;

template void read(T &x) {
    x = 0;
    char f = 0, c = getchar();
    while(!isdigit(c)) f = (c == '-'), c = getchar();
    if(f) while(isdigit(c)) x = x * 10 - c + 48, c = getchar();
    else while(isdigit(c)) x = x * 10 + c - 48, c = getchar();
}
template void bemin(T &x, T y) { if(x > y) x = y; }
template void bemax(T &x, T y) { if(x < y) x = y; }

const int N = 5e4 + 5, M = 2e5 + 5;

int n, m;

int ans[M];

struct range {
    int l, r, id;
} a[N], q[M];

bool cmpx(range X, range Y) {
    return X.l < Y.l;
}
bool cmpy(range X, range Y) {
    return X.r < Y.r;
}

struct KD_Tree {
    struct node {
	int xl, xr, yl, yr;
	int qtag, htag, mtag;
	bool tag0;
	node(int xl = 0, int xr = 0, int yl = 0, int yr = 0) {
	    this->xl = xl, this->xr = xr, this->yl = yl, this->yr = yr;
	    qtag = htag = mtag = 0, tag0 = false;
	}
    } T[M << 2];
    inline int ls(int now) { return now << 1; }
    inline int rs(int now) { return now << 1 | 1; }
    inline void push_down(int now) {
	node &x = T[now], &L = T[ls(now)], &R = T[rs(now)];
	if(!L.tag0) L.qtag += x.qtag;
	L.htag += x.qtag;
	if(!R.tag0) R.qtag += x.qtag;
	R.htag += x.qtag;
	if(x.tag0) {
	    L.mtag = max(L.mtag, max(L.htag, x.mtag));
	    L.htag = x.htag, L.tag0 = true;
	    R.mtag = max(R.mtag, max(R.htag, x.mtag));
	    R.htag = x.htag, R.tag0 = true;
	}
	x.qtag = x.htag = 0, x.tag0 = false;
    }
    inline void update(int now) {
	node &x = T[now], &L = T[ls(now)], &R = T[rs(now)];
	x.xl = min(L.xl, R.xl), x.xr = max(L.xr, R.xr);
	x.yl = min(L.yl, R.yl), x.yr = max(L.yr, R.yr);
    }
    void build(int l, int r, bool k = true, int now = 1) {
	if(l == r) {
	    T[now] = node(q[l].l, q[l].l, q[l].r, q[l].r);
	    return;
	}
	int mid = (l + r) >> 1;
	nth_element(q + l, q + mid, q + r + 1, k? cmpx : cmpy);
	build(l, mid, !k, ls(now)), build(mid + 1, r, !k, rs(now));
	update(now);
    }
    void add1(int xl, int xr, int yl, int yr, int now = 1) {
	node &x = T[now];
	if(x.xr < xl || x.xl > xr || x.yr < yl || x.yl > yr) return;
	if(xl <= x.xl && x.xr <= xr && yl <= x.yl && x.yr <= yr) {
	    if(!x.tag0) ++x.qtag;
	    ++x.htag;
	    return;
	}
	push_down(now);
	add1(xl, xr, yl, yr, ls(now)), add1(xl, xr, yl, yr, rs(now));
    }
    void change0(int xl, int xr, int yl, int yr, int now = 1) {
	node &x = T[now];
	if(x.xr < xl || x.xl > xr || x.yr < yl || x.yl > yr) return;
	if(xl <= x.xl && x.xr <= xr && yl <= x.yl && x.yr <= yr) {
	    x.mtag = max(x.mtag, x.htag);
	    x.htag = 0, x.tag0 = true;
	    return;
	}
	push_down(now);
	change0(xl, xr, yl, yr, ls(now)), change0(xl, xr, yl, yr, rs(now));
    }
    void get_ans(int l, int r, int now = 1) {
	if(l == r) {
	    ans[q[l].id] = max(T[now].htag, T[now].mtag);
	    return;
	}
	push_down(now);
	int mid = (l + r) >> 1;
	get_ans(l, mid, ls(now)), get_ans(mid + 1, r, rs(now));
    }
} kdt;



int main() {
    read(n), read(m);
    lep(i, 1, n) {
	read(a[i].l), read(a[i].r);
    }
    lep(i, 1, m) {
	read(q[i].l), read(q[i].r);
	q[i].id = i;
    }
    kdt.build(1, m);
    lep(i, 1, n) {
	int l = a[i].l, r = a[i].r;
	kdt.add1(1, r, l, 1e9);
	kdt.change0(1, 1e9, 1, l - 1);
	kdt.change0(r + 1, 1e9, 1, 1e9);
    }
    kdt.get_ans(1, m);
    lep(i, 1, m) {
	cout << ans[i] << "\n";
    }
    return 0;
}