COGS 577 蝗灾 cdq分治+树状数组

本文介绍了一道关于CDQ分治算法的经典题目,并详细解释了如何通过分治策略解决区间更新与查询的问题。文中提供了完整的C++代码实现,演示了如何对询问进行拆分并排序,最终高效地计算出每个询问的答案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:点击打开链接

cdq入门资料:点击打开链接

思路:首先根据上面的ppt可知cdq分治:

solve(l, mid);

计算[l,mid] 对 [mid+1, r] 区间的影响

solve(mid+1, r);

计算影响部分,把询问拆成2个,对x排序后搞搞即可。


#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <vector>
#include <string>
#include <time.h>
#include <math.h>
#include <queue>
#include <stack>
#include <set>
#include <map>
const double eps = 1e-8;
const double pi = acos(-1.0);
template <class T>
inline bool rd(T &ret) {
	char c; int sgn;
	if (c = getchar(), c == EOF) return 0;
	while (c != '-' && (c<'0' || c>'9')) c = getchar();
	sgn = (c == '-') ? -1 : 1;
	ret = (c == '-') ? 0 : (c - '0');
	while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
	ret *= sgn;
	return 1;
}
template <class T>
inline void pt(T x) {
	if (x <0) { putchar('-'); x = -x; }
	if (x>9) pt(x / 10);
	putchar(x % 10 + '0');
}
using namespace std;
typedef long long ll;
int c[500005], maxn;
inline int Lowbit(int x){ return x&(-x); }
void add(int i, int x){
	while (i <= maxn) c[i] += x,i += Lowbit(i);
}
int sum(int x){//区间求和 [1,x]
	int ans = 0;
	for (int i = x; i ; i -= Lowbit(i))
		ans += c[i];
	return ans;
}
const int N = 200005;
struct Q{
	int op, x1, y1, x2, y2, z, num, ans;
}q[N], cc[N<<1];
bool cmp(const Q&x, const Q&y){
	if (x.x1 == y.x1)return x.op < y.op;
	return x.x1 < y.x1;
}
int w, n;
int top;
void solve(int l, int r){
	if (l == r)return;
	int mid = (l + r) >> 1;
	top = 0;
	for (int i = l; i <= mid; i++)if (q[i].op == 1)cc[top++] = q[i];
	for (int i = mid + 1; i <= r; i++){
		if (q[i].op == 2){
			cc[top++] = q[i];
			cc[top++] = q[i];
			cc[top - 2].x1--;
			cc[top - 1].x1 = q[i].x2;
			cc[top - 1].op = 3;
		}
	}
	sort(cc, cc + top, cmp);
	for (int i = 0; i < top; i++){
		if (cc[i].op == 1)
			add(cc[i].y1, cc[i].z);
		else if (cc[i].op == 2)
			q[cc[i].num].ans -= sum(cc[i].y2) - sum(cc[i].y1 - 1);
		else
			q[cc[i].num].ans += sum(cc[i].y2) - sum(cc[i].y1 - 1);
	}
	for (int i = 0; i < top; i++)
	if (cc[i].op == 1)
		add(cc[i].y1, -cc[i].z);
	solve(l, mid); solve(mid + 1, r);
}
int main(){
	freopen("locust.in", "r", stdin);
	freopen("locust.out", "w", stdout);
	rd(w); rd(n);
	maxn = w;
	for (int i = 1, x1, y1, x2, y2; i <= n; i++){
		q[i].num = i;
		rd(q[i].op);
		if (q[i].op == 1){
			rd(q[i].x1); rd(q[i].y1); rd(q[i].z);
		}
		else {
			rd(x1); rd(y1); rd(x2); rd(y2);
			q[i].x1 = min(x1, x2); q[i].y1 = min(y1, y2);
			q[i].x2 = max(x1, x2); q[i].y2 = max(y1, y2);
		}
	}
	solve(1, n);
	for (int i = 1; i <= n; i++)
	if (q[i].op == 2)pt(q[i].ans), putchar('\n');
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值