P4145 上帝造题的七分钟2 / 花神游历各国 题解

题解 上帝造题的七分钟2 / 花神游历各国

Description

"第一分钟,X说,要有数列,于是便给定了一个正整数数列。

第二分钟,L说,要能修改,于是便有了对一段数中每个数都开平方(下取整)的操作。

第三分钟,k说,要能查询,于是便有了求一段数的和的操作。

第四分钟,彩虹喵说,要是noip难度,于是便有了数据范围。

第五分钟,诗人说,要有韵律,于是便有了时间限制和内存限制。

第六分钟,和雪说,要省点事,于是便有了保证运算过程中及最终结果均不超过64位有符号整数类型的表示范围的限制。

第七分钟,这道题终于造完了,然而,造题的神牛们再也不想写这道题的程序了。"

——《上帝造题的七分钟·第二部》

所以这个神圣的任务就交给你了。

SimpleInput

第一行一个整数 \(n\),代表数列中数的个数。

第二行 \(n\) 个正整数,表示初始状态下数列中的数。

第三行一个整数 \(m\),表示有 \(m\) 次操作。

接下来 \(m\) 行每行三个整数k,l,r,

  • k=0 表示给 \([l,r]\) 中的每个数开平方(下取整)
  • k=1 表示询问 \([l,r]\) 中各个数的和。

数据中有可能 \(l>r\),所以遇到这种情况请交换 \(l\)\(r\)

10
1 2 3 4 5 6 7 8 9 10
5
0 1 10
1 1 10
1 1 5
0 5 8
1 4 8

SimpleOutput

对于询问操作,每行输出一个回答。

19
7
6

数据范围

对于 \(30\%\) 的数据 \(1\le n,m\le 10^3\) 数列中的数不超过 32767。
对于 \(100\%\) 的数据 \(1\le n,m\le 10^5\) 数列中的数不超过 \(10^{12}\)

Solution

对于这道题目,我们考虑 分块
Q1:为什么不会出现鬼才TLE
A1:因为对于极限数据 \(10^{12}\) 开 6 次平方根之后就会变成 1,所以只有大概 6 倍的常数,适当卡常就可以通过
Q2:如何分块?
A2:暴力即可

由于过于鬼畜,所以直接放代码。

Code

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

const int N = 100009;

long long a[N],sum[N];
int l[N],r[N],belong[N];
bool visit[N];
int len,n,q,opt,L,R;

template <class T> inline void read(T &x) {
	x = 0;
	char ch = getchar();
	while(ch < '0' || ch > '9') ch = getchar();
	while(ch >= '0' && ch <= '9') {
		x = x * 10 + ch - '0';
		ch = getchar();
	}
}

inline void modify(int L,int R) {
	if(belong[L] == belong[R]) {
		if(visit[belong[L]]) return;
			for(register int i = L;i <= R;++i) {
				sum[belong[L]] -= a[i];
				a[i] = sqrt(a[i]);
				sum[belong[L]] += a[i];
			}
			if(sum[belong[L]] == r[belong[L]] - l[belong[L]] + 1) visit[belong[L]] = 1;
	}else {
		for(register int i = belong[L] + 1;i < belong[R];++i) {
			if(visit[i]) continue;
			for(register int j = l[i];j <= r[i];++j) {
				sum[i] -= a[j];
				a[j] = sqrt(a[j]);
				sum[i] += a[j];
			}
			if(sum[i] == r[i] - l[i] + 1) visit[i] = 1;
		}
		for(register int i = L;i <= r[belong[L]];++i) {
			sum[belong[L]] -= a[i];
			a[i] = sqrt(a[i]);
			sum[belong[L]] += a[i];
		}
		for(register int i = l[belong[R]];i <= R;++i) {
			sum[belong[R]] -= a[i];
			a[i] = sqrt(a[i]);
			sum[belong[R]] += a[i];
		}
		if(sum[belong[L]] == r[belong[L]] - l[belong[L]] + 1) visit[belong[L]] = 1;
		if(sum[belong[R]] == r[belong[R]] - l[belong[L]] + 1) visit[belong[R]] = 1;
	}
}

inline long long query(int L,int R) {
	long long ans = 0;
	if(belong[L] == belong[R]) {
		for(register int i = L;i <= R;++i) ans = ans + a[i];
	}else {
		for(register int i = belong[L] + 1;i < belong[R];++i) {
			ans = ans + sum[i];
		}
		for(register int i = L;i <= r[belong[L]];++i) ans += a[i];
		for(register int i = l[belong[R]];i <= R;++i) ans += a[i];
	}
	return ans;
}

int main() {
	read(n); len = sqrt(n);
	for(register int i = 1;i <= n;++i) {
		read(a[i]);
		belong[i] = i / len;
		sum[belong[i]] += a[i];
		if(!l[belong[i]]) l[belong[i]] = i;
		r[belong[i]] = i;
	}
	read(q);
	while(q--) {
		read(opt); read(L); read(R);
		if(L > R) swap(L,R);
		if(opt == 0) {
			modify(L,R);
		}else {
			printf("%lld\n",query(L,R));
		}
	}
	return 0;
}

其实当时交上去的时候,我还被卡常了 50pts,最后加了一点玄学才过,果然是人傻常数大。

posted @ 2020-11-18 19:49  SupperWeak  阅读(66)  评论(0)    收藏  举报