SPOJ GSS4 复杂度均摊

题意:

\(n\) 个数,和在 \(10^{18}\) 范围内。

也就是 \(\sum a_i \le10^{18}\)

现在有「两种」操作

0 x y 把区间 \([x,y]\) 内的每个数开方,下取整

1 x y询问区间 \([x,y]\) 的每个数的和

「格式」: 有多组数据,数据以 EOF 结束,对于每组数据,输出数据的序号,每组数据之后输出一个空行。

「注意」: 不保证给出的区间 \([x, y]\)\(x \le y\) ,如果 \(x>y\) 请交换 \(x,y\)


开方有一个性质
\[ \lfloor \sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{10^{18}}}}}}} \rfloor=1 \]
这就说明了,在这个数据范围内,一个数最多被“有效”开方 6 次,对 1 开方我们视为“无效”开方,因为 \(\sqrt1 =1\)

那么我们可以线段树维护两个值 \(sum_u\) 区间和以及 \(max_u\) 区间最大值

如果一个区间内最大值为 1 ,那么这个区间内的数无论开方多少次也不会变,所以就可以不用对这个区间进行操作

扫描二维码关注公众号,回复: 9659110 查看本文章

如果最大值不是 1,那么就对这个区间内那些不为 1 的点暴力开方,因为一个数最多被“有效”
开方 6 次,所以不会超时

// This code Write By chtholly_micromaker(MicroMaker)
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#define reg register
#define int long long
using namespace std;
const int MaxN=200001;
struct Node
{
    int val,sum;
};
template <class t> inline void rd(t &s)
{
    s=0;
    reg char c=getchar();
    while(!isdigit(c))
        c=getchar();
    while(isdigit(c))
        s=(s<<3)+(s<<1)+(c^48),c=getchar();
    return;
}
int a[MaxN],n;
struct SegTree
{
    #define rt (u>>1)
    #define lson (u<<1)
    #define rson (u<<1|1)
    Node tr[MaxN<<2];
    inline void clear()
    {
        memset(tr,0,sizeof tr);
        return;
    }
    inline void pushup(int u)
    {
        tr[u].val=max(tr[lson].val,tr[rson].val);
        tr[u].sum=tr[lson].sum+tr[rson].sum;
        return;
    }
    inline void buildtr(int u,int l,int r)
    {
        if(l==r)
        {
            tr[u].sum=tr[u].val=a[l];
            return;
        }
        reg int mid=(l+r)>>1;
        buildtr(lson,l,mid);
        buildtr(rson,mid+1,r);
        pushup(u);
        return;
    }
    /*
    inline void change(int u,int l,int r,int ql,int qr)
    {
        if(ql<=l&&r<=qr)
        {
            if(tr[u].val<=1)
                return;
            reg int maxi=0,res=0;
            for(int i=l;i<=r;++i)
                maxi=max(maxi,a[i]=sqrt(a[i])),res+=a[i];
            tr[u].val=maxi;
            tr[u].lazy=maxi;
            tr[u].sum=res;
//          printf("$$$  %d %d %d\n",l,r,res);
            return;
        }
        reg int mid=(l+r)>>1;
        if(ql<=mid)
            change(lson,l,mid,ql,qr);
        if(mid<qr)
            change(rson,mid+1,r,ql,qr);
        pushup(u);
        return;
    }*/
    inline void change(int u,int l,int r,int ql,int qr)
    {
        if(l==r)
        {
            tr[u].sum=sqrt(tr[u].sum);
            tr[u].val=tr[u].sum;
            return;
        }
        reg int mid=(l+r)>>1;
        if(ql<=mid&&tr[lson].val>1)
            change(lson,l,mid,ql,qr);
        if(mid<qr&&tr[rson].val>1)
            change(rson,mid+1,r,ql,qr);
        pushup(u);
        return;
    }
    inline int query(int u,int l,int r,int ql,int qr)
    {
        if(ql<=l&&r<=qr)
            return tr[u].sum;
//      pushdown(u,l,r);
        reg int mid=(l+r)>>1,res=0;
        if(ql<=mid)
            res+=query(lson,l,mid,ql,qr);
        if(mid<qr)
            res+=query(rson,mid+1,r,ql,qr);
        return res;
    }
}segtr;
inline void work()
{
    reg int opt,x,y;
    int m;
    segtr.clear();
    for(int i=1;i<=n;++i)
        rd(a[i]);
    segtr.buildtr(1,1,n);
    rd(m);
    for(int i=1;i<=m;++i)
    {
        rd(opt);rd(x);rd(y);
        if(x>y)
            swap(x,y);
        if(!opt)
            segtr.change(1,1,n,x,y);
        else
            printf("%lld\n",segtr.query(1,1,n,x,y));
    }
    return;
}
signed main(void)
{
//  freopen("test.out","w",stdout);
    int cnt=0;
    while(~scanf("%lld",&n))
    {
        printf("Case #%lld:\n",++cnt);
        work();
        puts("");
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/chinesepikaync/p/12441235.html
今日推荐