题解 SP2713 【GSS4

用计算器算一算,就可以发现(10^{18})的数,被开方(6)次后就变为了(1)

所以我们可以直接暴力的进行区间修改,若这个数已经到达(1),则以后就不再修改(因为(1)开方后还是(1)),用并查集和树状数组进行维护。

这个方法用了P2391 白雪皑皑的思想处理,用并查集标记该点已经不再用替换。

和我这题CF920F【SUM和REPLACE】的方法相同。

(code):

#include<bits/stdc++.h>
#define maxn 500010
#define lowbit(x) (x&(-x))
typedef long long ll;
using namespace std;
ll n,m;
ll fa[maxn],k,l,r;
ll a[maxn],tree[maxn];
int cnt;
int find(int x)
{
	return fa[x]==x?x:fa[x]=find(fa[x]);
}
void add(int x,ll d)
{
	while(x<=n)
	{
		tree[x]+=d;
		x+=lowbit(x);
	}
}
ll query(int x)
{
	ll sum=0;
	while(x)
	{
		sum+=tree[x];
		x-=lowbit(x);
	}
	return sum;
}
int main()
{
	while(scanf("%lld",&n)!=EOF)
	{
		cnt++;
		printf("Case #%d:
",cnt);
		for(int i=1;i<=n*4;++i)
		tree[i]=0;
		for(int i=1;i<=n;++i)
		{
			scanf("%lld",&a[i]);
			add(i,a[i]);
			fa[i]=i;
		}
		fa[n+1]=n+1;
		scanf("%lld",&m);
		while(m--)
		{
			scanf("%lld%lld%lld",&k,&l,&r);
			if(l>r)
			swap(l,r);
			if(k==0)
			{
				for(int i=l;i<=r;)
				{
					add(i,(ll)sqrt(a[i])-a[i]);//手动暴力开方
					a[i]=(ll)sqrt(a[i]);
					if(a[i]<=1)
					fa[i]=i+1;//若这个数已经为1,则将其指向它下一个数	
					if(i==find(i))
					i++;
					else
					i=fa[i];//进行跳转,忽略不再需要开方的数
				}
			}
			else
			printf("%lld
",query(r)-query(l-1));
		}
		printf("
");
	}
	return 0;
}
原文地址:https://www.cnblogs.com/lhm-/p/12229808.html