玄关求调 5pts WA#2~20
查看原帖
玄关求调 5pts WA#2~20
1097884
shuhao楼主2025/7/28 15:14

record

#include <iostream>
#include <cmath>
using namespace std;
#define LL long long

const int MAXN = 1e5 + 5;

int n, m;
int a[MAXN], rg[MAXN]; 	// a[i] 在第 rg[i] 个区间
int S, C = 0; 			// 总共有 C 个长度为 S 的区间
int sl[MAXN], sr[MAXN];	// 第 i 个区间为 [sl[i], sr[i]]
LL sum[MAXN]; 			// sum[i] = a[sl[i]] + a[sl[i] + 1] + ... + a[sr[i]]

inline void init() { // 初始化
	S = int(sqrt(double(n))); // 取平方根是最优的
	
	for (int i = 1; i <= n; i += S) {
		sl[++C] = i;
		sr[C] = min(i + S - 1, n); // sqrt 有精度误差
	}
	
	for (int i = 1; i <= C; ++i)
		for (int j = sl[i]; j <= sr[i]; ++j)
            {rg[j] = i; sum[i] += a[j];}
}

inline void update(int x, int k) {a[x] += k; sum[rg[x]] += k;} // 单点更新

int dt[MAXN]; // 若“1 x y k”中的 [x, y] 完整包含了第 i 个区间,则 dt[i] += k
inline void update_range(int x, int y, int k) { // 区间更新
	int l = rg[x], r = rg[y];
	if (l == r && sl[l] == x && sr[r] == y) {dt[l] = k; return ;}

	for (int i = x; i <= sr[l]; ++i) update(i, k);
	if(sl[l] < x && sr[r] > y) return ;
	for (int i = sl[r]; i <= y; ++i) update(i, k);

	for(int i = l + 1; i < r; ++i) dt[i] += k;
}

inline LL query(int x, int y) { // 询问
	int l = rg[x], r = rg[y]; LL ans = 0;
	if (l == r)
		for (int i = x; i <= y; ++i)
			ans += a[i] + dt[rg[i]];
	else {
		for (int i = x; i <= sr[l]; ++i)
			ans += a[i] + dt[rg[i]];
		for (int i = l + 1; i < r; ++i)
			ans += sum[i] + dt[i] * (sr[i] - sl[i] + 1);

		for (int i = sl[r]; i <= y; ++i)
			ans += a[i] + dt[rg[i]];
	}
	return ans;
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	
	cin >> n >> m;
	for (int i = 1; i <= n; ++i)
		cin >> a[i];

	init();

	while (m--) {
		int t; cin >> t;
		
		if (t == 1) {
			int x, y, k; cin >> x >> y >> k;
			update_range(x, y, k);
		} else if (t == 2) {
			int x, y; cin >> x >> y;
			cout << query(x, y) << '\n';
		}
	}

	return 0;
}

2025/7/28 15:14
加载中...