一,前言:
众所周知,有极其高级的数据结构,线段树,但是本人不会qwq。
(会用线段树解此题的神犇请移步。本人只是个蒟蒻,第一次写题解,如有不对,请谅解。)
二,解法:
因此,我想到了一个特别的解法树状数组。~~好像这章标题是线段树~~
可是,如果进行普通的解法,时间复杂度是相当高,因此,我想到了**并查集**。
通过观察可以得到,数据范围是10^9,经过几次开方就能四舍五入为`1`。
所以我们要用并查集维护
如果当前的数不等于1,直接把他的祖先变成他自己即f[i]=i 如果当前数等于1,也直接把f[i]变成下一个不等于1的数的位置即 f[i]=j,i<j<n,a[j]!=1
然后只用按题意,查找祖先是自己的数就可以。
最后才用树状数组维护 为什么并查集有这么多行(恼)
三,愉快的代码部分
#include<bits/stdc++.h>
#define maxn 100100
#define ll long long
using namespace std;
ll c[maxn*4],a[maxn];int fa[maxn],m,n,q,l,r,t;
int find(int x)
{
———删除部分———
}
void add(int x,ll y)
{
for (;x<=n;x+=x&-x)
{
c[x]+=y;//读入
}
}
ll ask(int x)
{
ll r=0;
for (;x;x-=x&-x)
{
r+=c[x];//输出
}
return r;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
add(i,a[i]);
fa[i]=i;//并查集
}
scanf("%d",&m);
————删除部分————
while(m--)
{
scanf("%d%d%d",&q,&l,&r);
if (q==1)
{
printf("%lld\n",ask(r)-ask(l-1));
}
else
{
for (int i = l; i <= r;)
{
int t = (int)sqrt(a[i]);
add(i, a[i]-t);
a[i] = t;
fa[i] = (a[i] <= 1) ? i + 1 : i;
int new_i = (find(i) == i) ? i + 1 : fa[i];//更新
i = new_i;
}
}
}
}
本人删除了一部分代码,防止抄袭。
题解借鉴