笛卡尔树

思路

如果说给你一个数组,有 \(q\) 组询问,询问一个区间的区间和,那么有最原始的做法。维护一个左端点和一个右端点,每次一位一位移动断点,那么时间复杂度是 \(n \times q\),那么如果我们将查询存起来,按一种我们想要的顺序去做呢?我们就可以排序,排序规则就是:

B = sqrt(n);
bool cmp(node _x, node _y) {
  if (_x.l / B != _y.l / B) {
    return _x.l / B < _y.l / B;
  }
  return _x.r < _y.r;
}

具体来说就是先将左端点分成一个一个的块,右端点则按从小到大排序即可。

时间复杂度

左端点在一个块内做多移动 \(n\) 次(|1,3,5,4,2|数字表示顺序),那么有 \(\sqrt{n}\) 的块,那就最多移动 \(n\times\sqrt{n}\)
右端点也是一样
那么时间复杂度就是 \(O(2\timesn\times\sqrt{n})\)
code:

#include <bits/stdc++.h>

using namespace std;

#define int long long

const int N = 2e5 + 5, B = 455;

struct node {
	int l, r, id;
}a[N];

int n, q, x[N], ans[N];

bool cmp(node _x, node _y) {
	if (_x.l / B != _y.l / B) {
		return _x.l / B < _y.l / B;
	}
	return _x.r < _y.r;
}

signed main() {
	cin >> n >> q;
	for (int i = 1; i <= n; i++) {
		cin >> x[i];
	}
	for (int i = 1; i <= q; i++) {
		cin >> a[i].l >> a[i].r;
		a[i].id = i; 
	}
	sort(a + 1, a + q + 1, cmp);
	for (int i = 1, lt = 1, rt = 1, tmp = x[1]; i <= q; i++) {
		while (lt < a[i].l) {				
			tmp -= x[lt];		
		  lt++;
		}
		while (rt < a[i].r) {				  
			rt++;		
		  tmp += x[rt];		
		}
		while (lt > a[i].l) {			
		  lt--;
			tmp += x[lt];
		}
		while (rt > a[i].r) {
			tmp -= x[rt];
			rt--;
		}
		ans[a[i].id] = tmp;
	}
	for (int i = 1; i <= q; i++) {
		cout << ans[i] << "\n";
	}
	return 0;
} 

优势

如:做算区间内有多少种颜色时极其方便

劣势

如:时间复杂度很劣,远远没有线段树优秀

#include <bits/stdc++.h>

using namespace std;

const int N = 2e5 + 5, B = 455;

struct node {
	int l, r, id;
}a[N];

int n, q, x[N], ans[N], cnt = 0, mp[N + 5];

vector<int> v;

bool cmp(node _x, node _y) {
	if (_x.l / B != _y.l / B) {
		return _x.l / B < _y.l / B;
	}
	return _x.r < _y.r;
}

void check(int u, int op) {
	if (op == 1) {
		if (!mp[u]) {
			cnt++;
		}
		mp[u]++;
	}
	else {
		mp[u]--;
		if (!mp[u]) {
			cnt--;
		}
	}
}

int main() {
	cin >> n >> q;
	for (int i = 1; i <= n; i++) {
		cin >> x[i];
		v.push_back(x[i]); 
	}
	sort(v.begin(), v.end());
	for (int i = 1; i <= n; i++) {
		x[i] = lower_bound(v.begin(), v.end(), x[i]) - v.begin(); 
	}
	for (int i = 1; i <= q; i++) {
		cin >> a[i].l >> a[i].r;
		a[i].id = i; 
	}
	sort(a + 1, a + q + 1, cmp);
	for (int i = 1, lt = 1, rt = 0; i <= q; i++) {
		while (lt < a[i].l) {				
			check(x[lt], -1);	
		  lt++;
		}
		while (rt < a[i].r) {				  
			rt++;	
			check(x[rt], 1);		
		}
		while (lt > a[i].l) {			
		  lt--;
			check(x[lt], 1);
		}
		while (rt > a[i].r) {
			check(x[rt], -1);
			rt--;
		}
		ans[a[i].id] = cnt;
	}
	for (int i = 1; i <= q; i++) {
		cout << ans[i] << "\n";
	}
	return 0;
} 
posted @ 2024-09-23 20:04  libohan0518  阅读(3)  评论(0编辑  收藏  举报