【BZOJ3211】花神游历各国 树状数组 并查集 均摊分析

来源:互联网 发布:windows安装在bootcamp 编辑:程序博客网 时间:2024/06/05 02:31

链接:

#include <stdio.h>int main(){    puts("转载请注明出处[vmurder]谢谢");    puts("网址:blog.csdn.net/vmurder/article/details/44686727");}

题解:

一个点开几次方就没啦。所以我们只需要修改不是0或者1的点就行了。
均摊基本O(n)
然后用并查集维护一个点右边第一个不是0的数。

手写读入果然高大上。卡rank神器。
顺便Orz一下wys大神。

代码:

#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define N 100100using 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);    }}
0 0