题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5828
给你n个数,m个操作,操作k,l,r,
k=1时 区间[l,r]每个数加x;
k=2时,区间[l,r]每个数开平方;
k=3时,求区间[l,r]的和。
开方的操作执行的次数,并不多到所以最后会出现很多相同的数,我们可以把相同的数统一减去一个数即可,但是数据中如果存在2 3 2 3 2 3 2 3,有10w次+6,然后开方,这样的话,时间复杂度也是很高的;所以我们可以看到,只要两个数相差一,开方后还相差一,那么我们可以减去一个数完成;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<algorithm> #include<string.h> #include<stdio.h> #include<math.h> using namespace std; #define N 100005 #define met(a, b) memset(a, b, sizeof(a)) #define mod 1000000007 typedef long long LL; #define Lson r<<1 #define Rson r<<1|1 struct Tree { int L, R; LL lazy, Min, Max, sum; int mid() { return (L+R)/2; } int len() { return (R-L+1); } }a[N<<2]; void BuildTree(int r, int L, int R) { a[r].L = L; a[r].R = R; a[r].lazy = 0; if(a[r].L == a[r].R) { scanf("%I64d", &a[r].sum); a[r].Max = a[r].Min = a[r].sum; return ; } BuildTree(Lson, L, a[r].mid()); BuildTree(Rson, a[r].mid()+1, R); a[r].sum = a[Lson].sum + a[Rson].sum; a[r].Max = max(a[Lson].Max, a[Rson].Max); a[r].Min = min(a[Lson].Min, a[Rson].Min); } void Down(int r) { a[Lson].lazy += a[r].lazy; a[Rson].lazy += a[r].lazy; a[Lson].sum += a[Lson].len()*a[r].lazy; a[Rson].sum += a[Rson].len()*a[r].lazy; a[Lson].Max += a[r].lazy; a[Rson].Max += a[r].lazy; a[Lson].Min += a[r].lazy; a[Rson].Min += a[r].lazy; a[r].lazy = 0; } void Up(int r) { a[r].sum = a[Lson].sum + a[Rson].sum; a[r].Max = max(a[Lson].Max, a[Rson].Max); a[r].Min = min(a[Lson].Min, a[Rson].Min); } void Update1(int r, int L, int R, LL num) { a[r].sum += (R-L+1) * num; if(a[r].L == L && a[r].R == R) { a[r].Max += num; a[r].Min += num; a[r].lazy += num; return ; } Down(r);///往下传递Lazy; if(R <= a[r].mid()) Update1(Lson, L, R, num); else if(L > a[r].mid()) Update1(Rson, L, R, num); else { Update1(Lson, L, a[r].mid(), num); Update1(Rson, a[r].mid()+1, R, num); } Up(r);///往上传递Lazy; } void Update2(int r, int L, int R) { if(a[r].L == L && a[r].R == R) { if(a[r].Min == a[r].Max)///当区间内所有的数都相等时,相当于区间内所有数都减去同一个数; { LL num = (LL)sqrt(a[r].Max) - a[r].Max; a[r].sum += a[r].len() * num; a[r].lazy += num; a[r].Max += num; a[r].Min += num; return; } else if(a[r].Min + 1 == a[r].Max)///当数之间相差<=1的时候并且开方之后还是相差1的话,那么他们可以通过加一个数得到; { LL num1 = (LL)sqrt(a[r].Max); LL num2 = (LL)sqrt(a[r].Min); if(num1 == num2+1) { LL num = num1 - a[r].Max; a[r].sum += a[r].len() * num; a[r].lazy += num; a[r].Max += num; a[r].Min += num; return; } } } Down(r); if(R <= a[r].mid()) Update2(Lson, L, R); else if(L > a[r].mid()) Update2(Rson, L, R); else { Update2(Lson, L, a[r].mid()); Update2(Rson, a[r].mid()+1, R); } Up(r); } LL Query(int r, int L, int R) { if(L == a[r].L && R == a[r].R) { return a[r].sum; } Down(r); if(R <= a[r].mid()) return Query(Lson, L, R); else if(L > a[r].mid()) return Query(Rson, L, R); else { LL ans1 = Query(Lson, L, a[r].mid()); LL ans2 = Query(Rson, a[r].mid()+1, R); return ans1 + ans2; } } int main() { int T; scanf("%d", &T); while(T--) { int n, m, op, L, R; LL num; scanf("%d %d", &n, &m); BuildTree(1, 1, n); while(m--) { scanf("%d", &op); if(op == 1) { scanf("%d %d %I64d", &L, &R, &num); Update1(1, L, R, num); } else if(op == 2) { scanf("%d %d", &L, &R); Update2(1, L, R); } else { scanf("%d %d", &L, &R); LL ans = Query(1, L, R); printf("%I64d ", ans); } } } return 0; }