UOJ#228. 基础数据结构练习题

sylvia 是一个热爱学习的女孩子,今天她想要学习数据结构技巧。

在看了一些博客学了一些姿势后,她想要找一些数据结构题来练练手。于是她的好朋友九条可怜酱给她出了一道题。

给出一个长度为 nn 的数列 AA,接下来有 mm 次操作,操作有三种:

  1. 对于所有的 i[l,r]i∈[l,r],将 AiAi 变成 Ai+xAi+x。
  2. 对于所有的 i[l,r]i∈[l,r],将 AiAi 变成 Ai−−√⌊Ai⌋。
  3. 对于所有的 i[l,r]i∈[l,r],询问 AiAi 的和。

作为一个不怎么熟练的初学者,sylvia 想了好久都没做出来。而可怜酱又外出旅游去了,一时间联系不上。于是她决定向你寻求帮助:你能帮她解决这个问题吗。

输入格式

第一行两个数:n,mn,m。

接下来一行 nn 个数 AiAi。

接下来 mm 行中,第 ii 行第一个数 titi 表示操作类型:

若 ti=1ti=1,则接下来三个整数 li,ri,xili,ri,xi,表示操作一。

若 ti=2ti=2,则接下来三个整数 li,rili,ri,表示操作二。

若 ti=3ti=3,则接下来三个整数 li,rili,ri,表示操作三。

输出格式

对于每个询问操作,输出一行表示答案。

样例一

input

5 5
1 2 3 4 5
1 3 5 2
2 1 4
3 2 4
2 3 5
3 1 5

output

5
6

样例二

见样例数据下载。

限制与约定

测试点编号 nn 的规模 mm 的规模 其他约定
1 n3000n≤3000 m3000m≤3000  
2
3
4 n100000n≤100000 m100000m≤100000 数据随机生成
5
6 ti1ti≠1
7
8  
9
10

对于所有数据,保证有 1lirin,1Ai,xi1051≤li≤ri≤n,1≤Ai,xi≤105

时间限制:1s1s

空间限制:256MB

总结:这种题一般是考虑什么暴力姿势不会炸

可以证明两个数一直开根号, 直到相等为止,最多loglog次

因此考虑暴力,一直暴力开根号到两数相等,然后相等后就可以转化为区间加

有一种特殊情况 如

9 8 

sqrt(9) = 3, sqrt(8) = 2

9 - 8 = 3 - 2

开根号后, 两数差值不变,这样的话,暴力就会被卡掉, 特判一下这种情况,转化为区间加

全得开 long long 

#include <bits/stdc++.h>
using namespace std;

#define LL long long
const int maxn = 4e5 + 7;
LL sum[maxn], tag[maxn], Max[maxn], Min[maxn];
int n, m, a[maxn];

int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') { if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar();}
	return x* f;
}
LL mmax(LL a, LL b) {return a > b ?a :b;}
LL mmin(LL a, LL b) {return a < b ?a :b;}
void pushdown(int o, int l, int r) {
	if(tag[o]) {
		int mid = (l + r) >> 1;
		tag[o << 1] += tag[o]; tag[o << 1 | 1] += tag[o];
		sum[o << 1] += (mid - l + 1) * tag[o]; sum[o << 1 | 1] += (r - mid) * tag[o];
		Max[o << 1] += tag[o]; Max[o << 1 | 1] += tag[o];
		Min[o << 1] += tag[o]; Min[o << 1 | 1] += tag[o];
		tag[o] = 0;
	}
}
void update(int o) {
	sum[o] = sum[o << 1] + sum[o << 1 | 1];
	Max[o] = mmax(Max[o << 1], Max[o << 1 | 1]);
	Min[o] = mmin(Min[o << 1], Min[o << 1 | 1]);
}
void Build(int o, int l, int r) {
	if(l == r) {
		sum[o] = Max[o] = Min[o] = a[l]; return;
	} int mid = (l + r) >> 1;
	Build(o << 1, l, mid); Build(o << 1 | 1, mid + 1, r);
	update(o);
}
LL Query(int o, int l, int r, int ql, int qr) {
	if(ql <= l && r <= qr) return sum[o];
	int mid = (l + r) >> 1;
	LL res = 0; pushdown(o, l, r);
	if(ql <= mid) res += Query(o << 1, l, mid, ql, qr);
	if(qr > mid) res += Query(o << 1 | 1, mid + 1, r, ql, qr);
	return res;
}
void Modify(int o, int l, int r, int ql, int qr, LL z) {
	if(ql <= l && r <= qr) {
		sum[o] += z * (r - l + 1); tag[o] += z;
		Max[o] += z; Min[o] += z; return;
	} int mid = (l + r) >> 1; pushdown(o, l, r);
	if(ql <= mid) Modify(o << 1, l, mid, ql, qr, z);
	if(qr > mid) Modify(o << 1 | 1, mid + 1, r, ql, qr, z);
	update(o);
}
void Sqrt(int o, int l, int r, int ql, int qr) {
	if(ql <= l && r <= qr) {
		if((Max[o] - Min[o] == (LL)sqrt(Max[o]) - (LL)sqrt(Min[o])) || (Max[o] == Min[o])) {
			LL z = (LL)sqrt(Max[o]) - Max[o];
			sum[o] += z * (r - l + 1); Max[o] += z;
			Min[o] += z; tag[o] += z; return;
		}
	} pushdown(o, l, r); 
	int mid = (l + r) >> 1;
	if(ql <= mid) Sqrt(o << 1, l, mid, ql, qr);
	if(qr > mid) Sqrt(o << 1 | 1, mid + 1, r, ql, qr);
	update(o);
}

int main() {
	n = read(); m = read();
	for (register int i = 1; i <= n; ++i) a[i] = read();
	Build(1, 1, n);
	while(m--) {
		int op, x, y; op = read(); x = read(); y = read();
		LL z;
		switch(op) {
			case 1: z = read(); Modify(1, 1, n, x, y, z); break;
			case 2: Sqrt(1, 1, n, x, y); break;
			case 3: printf("%lld\n", Query(1, 1, n, x, y));
		}
	} return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/oi-forever/p/9190055.html