#include <stdio.h>
int main()
{
puts("转载请注明出处[vmurder]谢谢");
puts("网址:blog.csdn.net/vmurder/article/details/44686727");
}
一个点开几次方就没啦。所以我们只需要修改不是0或者1的点就行了。
均摊基本
然后用并查集维护一个点右边第一个不是0的数。
手写读入果然高大上。卡rank神器。
顺便Orz一下wys大神。
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100100
using namespace std;
inline int getc() {
static const int L = 1 << 15;
static char buf[L], *S = buf, *T = buf;
if (S == T) {
T = (S = buf) + fread(buf, 1, L, stdin);
if (S == T)
return EOF;
}
return *S++;
}
inline int getint() {
int c;
while(!isdigit(c = getc()) && c != ‘-‘);
bool sign = c == ‘-‘;
int tmp = sign ? 0 : c - ‘0‘;
while(isdigit(c = getc()))
tmp = (tmp << 1) + (tmp << 3) + c - ‘0‘;
return sign ? -tmp : tmp;
}
int n,m,v[N],f[N];
long long a[N];
inline int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
inline void add(int x,int w)
{while(x<=n)a[x]+=w,x+=x&-x;}
inline long long ask(int x)
{
long long ret=0;
while(x)ret+=a[x],x-=x&-x;
return ret;
}
inline void edit(int l,int r)
{
for(;l<=r;l=find(l+1))
{
int t=(int)sqrt(v[l]);
add(l,t-v[l]),v[l]=t;
if(v[l]<=1)f[l]=find(l+1);
}
}
int main()
{
freopen("test.in","r",stdin);
int i,a,b,c;
n=getint();
for(i=1;i<=n+5;i++)f[i]=i;
for(i=1;i<=n;i++)
{
v[i]=getint();
if(v[i]<=1)f[i]=i+1;
add(i,v[i]);
}
for(m=getint();m--;)
{
a=getint(),b=getint(),c=getint();
if(a==1)printf("%lld\n",ask(c)-ask(b-1));
else edit(b,c);
}
}
【BZOJ3211】花神游历各国 树状数组 并查集 均摊分析
原文:http://blog.csdn.net/vmurder/article/details/44686727