【BZOJ】3038: 上帝造题的七分钟2(线段树+暴力)

时间:2023-03-09 02:04:48
【BZOJ】3038: 上帝造题的七分钟2(线段树+暴力)

http://www.lydsy.com:808/JudgeOnline/problem.php?id=3038

【BZOJ】3038: 上帝造题的七分钟2(线段树+暴力)

这题我就有得吐槽了,先是线段树更新写错,然后不知哪没pushup导致te,精度问题sqrt没有开ll又wa,最终。。才acTAT,我容易吗我?第一次a后我测试了,还真是sqrt精度和flag问题TAT

这题更新sqrt暴力更新就行了,只需要注意,当sum=1或sum=0时就不必向下更新了,,这是一个小小的优化

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
#define rep(i, n) for(int i=0; i<(n); ++i)
#define for1(i,a,n) for(int i=(a);i<=(n);++i)
#define for2(i,a,n) for(int i=(a);i<(n);++i)
#define for3(i,a,n) for(int i=(a);i>=(n);--i)
#define for4(i,a,n) for(int i=(a);i>(n);--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define read(a) a=getnum()
#define print(a) printf("%d", a)
#define lc (rt << 1)
#define rc (rt << 1|1)
#define lson l, m, lc
#define rson m+1, r, rc
#define MID (l+r)>>1 inline long long getnum() { long long ret=0; char c; for(c=getchar(); c<'0' || c>'9'; c=getchar()); for(; c>='0' && c<='9'; c=getchar()) ret=ret*10+c-'0'; return ret; } const int N=500001;
int L, R;
long long sum[N];
bool flag[N]; inline void pushup(const int &rt) { sum[rt]=sum[lc]+sum[rc]; flag[rt]=flag[lc]&flag[rc]; } void build(const int &l, const int &r, const int &rt) {
if(l==r) {
sum[rt]=getnum();
if(sum[rt]==1||sum[rt]==0) flag[rt]=true;
return;
}
int m=MID;
build(lson); build(rson);
pushup(rt);
} void update(const int &l, const int &r, const int &rt) {
if(flag[rt]) return;
if(l==r) {
sum[rt]=(long long)sqrt(sum[rt]);
if(sum[rt]==1||sum[rt]==0) flag[rt]=true;
return;
}
int m=MID;
if(L<=m) update(lson);
if(m<R) update(rson);
pushup(rt);
} long long query(const int &l, const int &r, const int &rt) {
if(L<=l && r<=R) return sum[rt];
int m=MID;
long long ret=0;
if(L<=m) ret+=query(lson);
if(m<R) ret+=query(rson);
return ret;
} int main() {
int n=getnum();
build(1, n, 1);
L=1, R=n;
int m=getnum(), c;
while(m--) {
c=getnum();
read(L); read(R);
if(L>R) swap(L, R);
if(c) printf("%lld\n", query(1, n, 1));
else update(1, n, 1);
}
return 0;
}

Description

XLk觉得《上帝造题的七分钟》不太过瘾,于是有了第二部。
"第一分钟,X说,要有数列,于是便给定了一个正整数数列。
第二分钟,L说,要能修改,于是便有了对一段数中每个数都开平方(下取整)的操作。
第三分钟,k说,要能查询,于是便有了求一段数的和的操作。
第四分钟,彩虹喵说,要是noip难度,于是便有了数据范围。
第五分钟,诗人说,要有韵律,于是便有了时间限制和内存限制。
第六分钟,和雪说,要省点事,于是便有了保证运算过程中及最终结果均不超过64位有符号整数类型的表示范围的限制。
第七分钟,这道题终于造完了,然而,造题的神牛们再也不想写这道题的程序了。"
——《上帝造题的七分钟·第二部》
所以这个神圣的任务就交给你了。

Input

第一行一个整数n,代表数列中数的个数。
第二行n个正整数,表示初始状态下数列中的数。
第三行一个整数m,表示有m次操作。
接下来m行每行三个整数k,l,r,k=0表示给[l,r]中的每个数开平方(下取整),k=1表示询问[l,r]中各个数的和。

Output

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

Sample Input

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

Sample Output

19
7
6

HINT

1:对于100%的数据,1<=n<=100000,1<=l<=r<=n,数列中的数大于0,且不超过1e12。

2:数据不保证L<=R 若L>R,请自行交换L,R,谢谢!

Source