正题
题目链接:https://www.luogu.com.cn/problem/P4145
题目大意
一个序列要求支持
- 区间开根向下取整
- 区间求和
解题思路
一个数开根约logloglog次就会到111,所以我们对于每个数记录一下开根多少次会到111,每次修改用并查集找还没到111的暴力修改树状数组上的值即可。
时间复杂度O(nlog2n)O(n\log^2 n)O(nlog2n)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define lowbit(x) x&-x
using namespace std;
const ll N=1e5+10;
ll n,m,fa[N],t[N],a[N],w[N];
void Change(ll x,ll val){while(x<=n){t[x]+=val;x+=lowbit(x);}
}
ll Ask(ll x){ll ans=0;while(x){ans+=t[x];x-=lowbit(x);}return ans;
}
ll find(ll x)
{return (fa[x]==x)?(x):(fa[x]=find(fa[x]));}
void Move(ll x){ll k=sqrt(w[x]);a[x]--;Change(x,-w[x]+k);w[x]=k;if(!a[x]){if(!a[x+1]&&x<n)fa[x]=find(x+1);if(!a[x-1]&&x>1)fa[x-1]=find(x);}return;
}
int main()
{scanf("%lld",&n);for(ll i=1;i<=n;i++){fa[i]=i;ll x;scanf("%lld",&x);w[i]=x;Change(i,x);while(x>1){a[i]++;x=sqrt(x);}}scanf("%lld",&m);for(ll i=1;i<=m;i++){ll k,l,r;scanf("%lld%lld%lld",&k,&l,&r);if(l>r)swap(l,r);if(k==0){while(l<=r&&l){if(a[l])Move(l);l=find(l)+1;}}else printf("%lld\n",Ask(r)-Ask(l-1));}return 0;
}