思維題
樹狀數組+並查集維護
思路
發現最大數開根號最大也就開,所以我們每次開根號暴力修改,一個數最多也就被暴力修改6次就不會變了,然後我們就可以跳過這個數了,所以我們需要一個可以把它和他下一個連起來的東西,所以我們用了並查集,每次把一個數改成1之後,就把他和他下一個連起來,然後在樹狀數組上更新就好了
代碼
//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lowbit(x) x&(-x)
#define lli long long int
using namespace std;
const int M=200500;
int fa[M];
lli a[M],s[M],n,m;
inline void read(lli &x)
{
x=0;char ch=getchar();
while (!isdigit(ch)) ch=getchar();
while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return ;
}
inline void write(lli x)
{
if (x>9) write(x/10);
putchar(x%10+'0');
return ;
}
inline int find(int x)
{
if (x==fa[x]) return x;
return fa[x]=find(fa[x]);
}
inline void add(int p,lli x)
{
for (int i=p;i<=n;i+=lowbit(i)) s[i]+=x;
return ;
}
inline lli sum(int p)
{
lli su=0;
for (int i=p;i;i-=lowbit(i)) su+=s[i];
return su;
}
signed main()
{
read(n);
for (int i=1;i<=n;i++)
read(a[i]),add(i,a[i]),fa[i]=(a[i]==1?i+1:i);
read(m);fa[n+1]=n+1;
while (m--)
{
lli fl,x,y;
read(fl);read(x);read(y);
if (x>y) swap(x,y);
if (fl==1) write(sum(y)-sum(x-1)),puts("");
else
for (int i=x;i<=y;)
{
int t=sqrt(a[i]);
add(i,t-a[i]);a[i]=t;
fa[i]=(a[i]<=1)?i+1:i;
i=(find(i)==i?i+1:fa[i]);
}
}
return 0;
}