SPOJ GSS4 Can you answer these queries IV ——树状数组 并查集
【题目分析】
区间开方+区间求和。
由于区间开方次数较少,直接并查集维护下一个不是1的数的位置,然后暴力修改,树状数组求和即可。
这不是BZOJ上上帝造题7分钟嘛
【代码】
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define ll long long using namespace std; long long a[100001],f[100001],n,q,op,l,r; long long t[100001]; inline long long gf(long long k) { if (f[k]==k) return k; else return f[k]=gf(f[k]); } inline void add(long long x,long long f) { for (;x<=n;x+=x&(-x)) t[x]+=(ll)f; } inline long long gs(long long x) { long long ret=0; for (;x;x-=x&(-x)) ret+=t[x]; return ret; } int main() { int kas=0; while (scanf("%lld",&n)!=EOF) { printf("Case #%d:\n",++kas); memset(t,0,sizeof t); for (long long i=1;i<=n;++i) scanf("%lld",&a[i]),f[i]=i; f[n+1]=n+1; for (long long i=1;i<=n;++i) add(i,a[i]); scanf("%lld",&q); for (long long zz=1;zz<=q;++zz) { scanf("%lld",&op); if (op==0) { scanf("%lld%lld",&l,&r); if (l>r) swap(l,r); long long i=l; while (i<=r) { i=gf(f[i]); if (i>r) break; long long tmp=a[i]; a[i]=(long long)sqrt(a[i]); add(i,a[i]-tmp); if (a[i]==1) f[i]=f[i]+1; gf(f[i]); i++; } } else { scanf("%lld%lld",&l,&r); if (l>r) swap(l,r); printf("%lld\n",gs(r)-gs(l-1)); } } printf("\n"); } }