原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=5828
Rikka with Sequence
Problem Description
As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them:
Yuta has an array A with n numbers. Then he makes m operations on it.
There are three type of operations:
1 l r x : For each i in [l,r], change A[i] to A[i]+x
2 l r : For each i in [l,r], change A[i] to ⌊A−−√[i]⌋
3 l r : Yuta wants Rikka to sum up A[i] for all i in [l,r]
It is too difficult for Rikka. Can you help her?
Input
The first line contains a number t(1<=t<=100), the number of the testcases. And there are no more than 5 testcases with n>1000.
For each testcase, the first line contains two numbers n,m(1<=n,m<=100000). The second line contains n numbers A[1]~A[n]. Then m lines follow, each line describe an operation.
It is guaranteed that 1<=A[i],x<=100000.
Output
For each operation of type 3, print a lines contains one number – the answer of the query.
Sample Input
1
5 5
1 2 3 4 5
1 3 5 2
2 1 4
3 2 4
2 3 5
3 1 5
Sample Output
5
6
题解
根据上帝造题的7分钟的思路,开根操作会让区间内的数变得越来越一样,所以不妨记录一下区间最大值和最小值的大小以及个数,这样在 max−min≤1 m a x − m i n ≤ 1 的时候我们就可以直接计算出开根操作对区间的影响,当开根后 max=min m a x = m i n 时还需要一个区间赋值操作。
代码
#include<bits/stdc++.h>
#define ll long long
#define ls v<<1
#define rs v<<1|1
using namespace std;
const int M=4e5+5;
ll que[M],mx[M],mn[M],cmax[M],cmin[M],sum[M],tag[M],same[M];
int n,m;
void in(){scanf("%d%d",&n,&m);for(int i=1;i<=n;++i)scanf("%lld",&que[i]);}
void up(int v)
{
sum[v]=sum[ls]+sum[rs],cmax[v]=cmin[v]=0;
mx[v]=max(mx[ls],mx[rs]),mn[v]=min(mn[ls],mn[rs]);
if(mx[ls]>=mx[rs])cmax[v]+=cmax[ls];if(mx[ls]<=mx[rs])cmax[v]+=cmax[rs];
if(mn[ls]<=mn[rs])cmin[v]+=cmin[ls];if(mn[ls]>=mn[rs])cmin[v]+=cmin[rs];
}
void push(int v,int le,int ri)
{
int mid=le+ri>>1;
if(~same[v])
{
same[ls]=same[rs]=same[v],mx[ls]=mx[rs]=mn[ls]=mn[rs]=same[v],tag[ls]=tag[rs]=0,same[v]=-1;
sum[ls]=same[ls]*(cmax[ls]=cmin[ls]=mid-le+1),sum[rs]=same[rs]*(cmax[rs]=cmin[rs]=ri-mid);
}
if(tag[v])
{
tag[ls]+=tag[v],mx[ls]+=tag[v],mn[ls]+=tag[v],tag[rs]+=tag[v],mx[rs]+=tag[v],mn[rs]+=tag[v];
sum[ls]+=(mid-le+1)*tag[v],sum[rs]+=(ri-mid)*tag[v];
tag[v]=0;
}
}
void build(int v,int le,int ri)
{
same[v]=-1;tag[v]=0;
if(le==ri){mx[v]=mn[v]=sum[v]=que[le],cmax[v]=cmin[v]=1;return;}
int mid=le+ri>>1;
build(ls,le,mid);build(rs,mid+1,ri);
up(v);
}
void add(int v,int le,int ri,int lb,int rb,int d)
{
if(lb<=le&&ri<=rb){tag[v]+=d,mx[v]+=d,mn[v]+=d,sum[v]+=1ll*(ri-le+1)*d;return;}
int mid=le+ri>>1;push(v,le,ri);
if(lb<=mid)add(ls,le,mid,lb,rb,d);if(mid<rb)add(rs,mid+1,ri,lb,rb,d);
up(v);
}
void root(int v,int le,int ri,int lb,int rb)
{
if(le==ri){sum[v]=mx[v]=mn[v]=(ll)sqrt(mx[v]);return;}
if(lb<=le&&ri<=rb&&mx[v]-mn[v]<=1)
{
if(mx[v]==mn[v])same[v]=mx[v]=mn[v]=(ll)sqrt(mn[v]),cmax[v]=cmin[v]=ri-le+1,sum[v]=mx[v]*cmax[v],tag[v]=0;
else
{
ll pre=mx[v];mx[v]=(ll)sqrt(mx[v]),mn[v]=(ll)sqrt(mn[v]);
if(mx[v]==mn[v])same[v]=mx[v],cmax[v]=cmin[v]=ri-le+1,sum[v]=mx[v]*cmax[v],tag[v]=0;
else tag[v]+=mx[v]-pre,sum[v]=mx[v]*cmax[v]+mn[v]*cmin[v];
}
return;
}
int mid=le+ri>>1;push(v,le,ri);
if(lb<=mid)root(ls,le,mid,lb,rb);if(mid<rb)root(rs,mid+1,ri,lb,rb);
up(v);
}
ll ask(int v,int le,int ri,int lb,int rb)
{
if(lb<=le&&ri<=rb){return sum[v];}
int mid=le+ri>>1;ll ans=0;push(v,le,ri);
if(lb<=mid)ans=ask(ls,le,mid,lb,rb);if(mid<rb)ans+=ask(rs,mid+1,ri,lb,rb);
up(v);return ans;
}
void ac()
{
build(1,1,n);
int op,l,r,x;
for(int i=1;i<=m;++i)
{
scanf("%d%d%d",&op,&l,&r);
if(op==1){scanf("%d",&x);add(1,1,n,l,r,x);}
else if(op==2)root(1,1,n,l,r);
else printf("%lld\n",ask(1,1,n,l,r));
}
}
int main(){int T;scanf("%d",&T);while(T--)in(),ac();}