CDQ分治小结

CDQ分治小结

P3810三维偏序(陌上花开)

一道CDQ分治的比较模板又不是模板的问题.

\(f_i\)表示\(a_j<=a_i\)\(b_j<=b_i\)\(c_j<=c_i\)\(j\)的数量

对于\(d\in[0,n)\)让你求\(f(i) == d\)的数量

其实个人感觉模板的话

还是严格小于比较好做

先来考虑一下严格小于该怎么做

我们先对整体按照\(a_i\)排序,这样的话我们进行的分治就满足了第一个限制

之后我们试想一下,如果要求左区间对于右区间的贡献

我们只需要将两边分别排序

虽然这样两边就不一定在满足\(a_i\)的限制,但是左右两个区间依旧满足(因为我们是分别排序)

直接用权值树状数组计算右边对与左边的贡献

但是,如果要求小于等于,就要考虑有两个值其\(a_I,b_i,c_i\)均相同的情况

这样的话我们就去重

将重复\(n\)个的元素的权值改为\(n\)

最后

\(cnt_{ai.ans + ai.val-1}+=ai.ans\)

即可

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cctype>
#include<queue>
#include<stack>
using namespace std;
const int N = 1e5 + 3;
const int M = 2e5 + 3;
int n,k;
struct BIT{
	int c[M];
	inline int lowbit(int x){return x & -x;}
	inline void ins(int x,int v){
		for(;x <= k;x += lowbit(x)) c[x] += v;
	}
	inline int query(int x){
		int res = 0;
		for(;x;x -= lowbit(x)) res += c[x];
		return res;	
	}
}T;
struct node{
	int x,y,z;
	int val,ans;	
}a[N],b[N];
int cnt[N];
inline int read(){
	char ch = getchar();int v = 0,c = 1;
	while(!isdigit(ch)){
		if(ch == '-') c = -1;
		ch = getchar();	
	}
	while(isdigit(ch)){
		v = v * 10 + ch - 48;
		ch = getchar();	
	}
	return v * c;	
}
inline bool cmpx(node xx,node yy){
	if(xx.x != yy.x)
	return xx.x < yy.x;
	if(xx.y != yy.y)
	return xx.y < yy.y;
	return xx.z < yy.z;
}
inline bool cmpy(node xx,node yy){
	if(xx.y != yy.y)
	return xx.y < yy.y;
	return xx.z < yy.z;
}	
inline void solve(int l,int r){
	if(l == r) return ;
	int mid = (l + r) >> 1;
	solve(l,mid);solve(mid + 1,r);
//	printf("l:%d r:%d\n",l,r);
	sort(a + l,a + mid + 1,cmpy);
	sort(a + mid + 1,a + r + 1,cmpy);
//	for(int i = l;i <= r;++i) printf("%d %d\n",a[i].y,a[i].z);
	int top = l;
	for(int i = mid + 1;i <= r;++i){
		for(;top <= mid && a[top].y <= a[i].y;top++)
		T.ins(a[top].z,a[top].val);
	//	printf("%d %d %d\n",top,i,T.query(a[i].z));
		a[i].ans += T.query(a[i].z);
	}
	for(int i = l;i < top;++i) T.ins(a[i].z,-a[i].val);
}
int main(){
	n = read(),k = read();
	for(int i = 1;i <= n;++i)
		b[i].x = read(),b[i].y = read(),b[i].z = read();
	sort(b + 1,b + n + 1,cmpx);
	int c = 0,num = 0;
	for(int i = 1;i <= n;++i){
		c++;
		if(b[i].x != b[i + 1].x || b[i].y != b[i + 1].y || b[i].z != b[i + 1].z)
		a[++num] = b[i],a[num].val = c,c = 0;
	}
	swap(num,n);//for(int i = 1;i <= n;++i) printf("%d %d %d %d\n",a[i].x,a[i].y,a[i].z,a[i].val);
	solve(1,n);
//	for(int i = 1;i <= n;++i) printf("%d ",a[i].ans);puts("");
	for(int i = 1;i <= n;++i) cnt[a[i].ans + a[i].val - 1] += a[i].val;
	for(int i = 0;i < num;++i) printf("%d\n",cnt[i]);
	return 0;	
}

CF669E. Little Artem and Time Machine

CDQ的板子题了

我们以输入的操作顺序为第一维

操作的时间为第二维

第三维就直接查询有多少数等于他就好了

但是由于排序是将

sort(a + l,a + mid + 1,cmp)

写成了

sort(a + l + 1,a + mid + 1,cmp)

然后,调了一下午,还去找\(wqy\)学长丢人

#include<cstdio>
#include<cstring>
#include<cctype>
#include<map>
#include<algorithm>
#include<iostream>
#define LL long long
using namespace std;
const int N = 1e5 + 3;
int n;
struct Q{
	int type;
	LL time;
	LL val;
	int id;
	int ans;
}a[N];
map <LL,int> m;
inline LL read(){
	char ch = getchar();long long v = 0,c = 1;
	while(!isdigit(ch)){
		if(ch == '-') c = -1;
		ch = getchar();	
	}
	while(isdigit(ch)){
		v = v * 10 + ch - 48;
		ch = getchar();	
	}
	return v * c;	
}
inline bool cmp(Q x,Q y){
	return x.time < y.time;	
}
inline bool cmp2(Q x,Q y){
	return x.id < y.id;
}
inline void solve(int l,int r){
	if(l == r) return ;
	int mid = (l + r) >> 1;
	solve(l,mid);solve(mid + 1,r);
//	printf("l:%d r:%d\n",l,r);
	sort(a + l,a + mid + 1,cmp);
	sort(a + mid + 1,a + r + 1,cmp);
//	for(int i = l;i <= mid;++i) printf("%d %lld %lld\n",a[i].type,a[i].time,a[i].val);
//	printf("---------------\n");
//	for(int i = mid + 1;i <= r;++i) printf("%d %lld %lld\n",a[i].type,a[i].time,a[i].val);
	int top = l;
	for(int i = mid + 1;i <= r;++i){
		while(i <= r && a[i].type != 3) ++i;
		if(i > r) break;
		while(top <= mid && a[top].time <= a[i].time){
			if(a[top].type == 1) m[a[top].val]++;
			else if(a[top].type == 2) m[a[top].val]--;
			top++;
		}
		a[i].ans += m[a[i].val];
	}
	m.clear();
}
int main(){
	n = read();
	for(int i = 1;i <= n;++i){
		a[i].type = read();
		a[i].time = read();
		a[i].val = read();
		a[i].id = i;
	}
	solve(1,n);
	sort(a + 1,a + n + 1,cmp2); 
	for(int i = 1;i <= n;++i) if(a[i].type == 3) printf("%d\n",a[i].ans);
	return 0;	
posted @ 2019-05-12 21:34  wyxdrqcccc  阅读(180)  评论(0编辑  收藏  举报