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

链接:

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

题解:

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

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

代码:

#include 
#include 
#include 
#include 
#include 
#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,花神游历各国,树状数组,并查集,均摊分析)