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");
	}
}

  

posted @ 2017-02-01 20:02  SfailSth  阅读(150)  评论(0编辑  收藏  举报