Note - CDQ 套 CDQ

不难的,如果你会 CDQ。

给代码:

struct Node{
	int a, b, c, d;
	int val, dp, flag;
	bool operator==(Node o){return a==o.a&&b==o.b&&c==o.c&&d==o.d;}
} a[N];

int fwk[N];
#define lowbit(x) (x&-x)
inline void modify(int x, int k){for(int i = x; i <= k4; i += lowbit(i)) fwk[i] = max(fwk[i], k);}
inline int query(int x){int res = 0; for(int i = x; i; i ^= lowbit(i)) res = max(res, fwk[i]); return res;}
inline void clear(int x){for(int i = x; i <= k4; i += lowbit(i)) fwk[i] = 0;}

#define mid ((l+r)>>1)
inline void cdq3d(int l, int r){
	if(l == r) return;
	cdq3d(l, mid);
	sort(a+l, a+mid+1,   [&](Node o1, Node o2){return o1.c<o2.c||(o1.c==o2.c&&(o1.d<o2.d||(o1.d==o2.d&&(o1.a<o2.a||(o1.a==o2.a&&o1.b<o2.b)))));});
	sort(a+mid+1, a+r+1, [&](Node o1, Node o2){return o1.c<o2.c||(o1.c==o2.c&&(o1.d<o2.d||(o1.d==o2.d&&(o1.a<o2.a||(o1.a==o2.a&&o1.b<o2.b)))));});
	int i = l, j = mid+1;
	while(j <= r){
		while(i <= mid && a[j].c >= a[i].c){
			if(a[i].flag) modify(a[i].d, a[i].dp);
			++i;
		}
		if(!a[j].flag) a[j].dp = max(a[j].dp, query(a[j].d)+a[j].val);
		++j;
	}
	while(i > l){
		--i;
		if(a[i].flag) clear(a[i].d);
	}
	sort(a+mid+1, a+r+1, [&](Node o1, Node o2){return o1.b<o2.b||(o1.b==o2.b&&(o1.c<o2.c||(o1.c==o2.c&&(o1.d<o2.d||(o1.d==o2.d&&o1.a<o2.a)))));});
	cdq3d(mid+1, r);
	return;
}
inline void cdq4d(int l, int r){
	if(l == r) return;
	cdq4d(l, mid);
	for(int i = l; i <= mid;   ++i) a[i].flag = true;
	for(int i = mid+1; i <= r; ++i) a[i].flag = false;
	sort(a+l, a+r+1, [&](Node o1, Node o2){return o1.b<o2.b||(o1.b==o2.b&&(o1.c<o2.c||(o1.c==o2.c&&(o1.d<o2.d||(o1.d==o2.d&&o1.a<o2.a)))));});
	cdq3d(l, r);
	sort(a+l, a+r+1, [&](Node o1, Node o2){return o1.a<o2.a||(o1.a==o2.a&&(o1.b<o2.b||(o1.b==o2.b&&(o1.c<o2.c||(o1.c==o2.c&&o1.d<o2.d)))));});
	cdq4d(mid+1, r);
	return;
}

我们可以使用第一层 CDQ 标记一个点在最外层 left 还是 right,即第一维较小还是较大,确保了第一维的顺序。

然后进行第二层 CDQ。在这里,left 的点的第二维一定小于 right,确保了第二维的顺序。

然后在归并排序中,确保了第三维的顺序。

最后树状数组确保了第四维的顺序。

posted @ 2026-02-04 16:13  Hootime  阅读(0)  评论(0)    收藏  举报