mcfx's blog

题解、Writeup、游记和碎碎念

BZOJ 3038: 上帝造题的七分钟2

XLk 觉得《上帝造题的七分钟》不太过瘾,于是有了第二部。 "第一分钟,X 说,要有数列,于是便给定了一个正整数数列。 第二分钟,L 说,要能修改,于是便有了对一段数中每个数都开平方(下取整)的操作。 第三分钟,k 说,要能查询,于是便有了求一段数的和的操作。 第四分钟,彩虹喵说,要是 noip 难度,于是便有了数据范围。 第五分钟,诗人说,要有韵律,于是便有了时间限制和内存限制。 第六分钟,和雪说,要省点事,于是便有了保证运算过程中及最终结果均不超过 64 位有符号整数类型的表示范围的限制。 第七分钟,这道题终于造完了,然而,造题的神牛们再也不想写这道题的程序了。" ——《上帝造题的七分钟·第二部》 所以这个神圣的任务就交给你了。

Input

第一行一个整数 n,代表数列中数的个数。 第二行 n 个正整数,表示初始状态下数列中的数。 第三行一个整数 m,表示有 m 次操作。 接下来 m 行每行三个整数 k,l,r,k=0 表示给[l,r]中的每个数开平方(下取整),k=1 表示询问[l,r]中各个数的和。

Output

对于询问操作,每行输出一个回答。

Sample Input

10
1 2 3 4 5 6 7 8 9 10
5
0 1 10
1 1 10
1 1 5
0 5 8
1 4 8

Sample Output

19
7
6

Solution

显然,一个数最多开根 6 次就会变成 1,那么直接用线段树维护区间最大值,每次暴力修改即可。

Code

#include<bits/stdc++.h>

typedef unsigned char uchar;
typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;

#define xx first
#define yy second

template<typename T> inline T max(T a,T b){return a>b?a:b;}
template<typename T> inline T min(T a,T b){return a<b?a:b;}
template<typename T> inline T abs(T a){return a>0?a:-a;}
template<typename T> inline void repr(T &a,T b){if(a<b)a=b;}
template<typename T> inline void repl(T &a,T b){if(a>b)a=b;}
#define mp(a,b) std::make_pair(a,b)
#define pb push_back

int n,t=1;
ll s[270000],ma[270000];

inline void up(int x)
{
    s[x]=s[x<<1]+s[x<<1|1];
    ma[x]=max(ma[x<<1],ma[x<<1|1]);
}

void modify(int x,int l,int r,int ql,int qr)
{
    if(ma[x]<=1)return;
    if(x&t)
    {
        ma[x]=sqrt(ma[x]);
        s[x]=ma[x];
        return;
    }
    int q=(l+r)>>1;
    if(ql<q)modify(x<<1,l,q,ql,min(q,qr));
    if(qr>q)modify(x<<1|1,q,r,max(q,ql),qr);
    up(x);
}

int main()
{
    int m;
    scanf("%d",&n);
    while(t<n+2)t<<=1;
    for(int i=1;i<=n;i++)
        scanf("%lld",ma+i+t),s[i+t]=ma[i+t];
    for(int i=t-1;i;i--)
        up(i);
    scanf("%d",&m);
    while(m--)
    {
        int opt,x,y;
        scanf("%d%d%d",&opt,&x,&y);
        if(x>y)std::swap(x,y);
        if(opt==0)
        {
            modify(1,1,t,x,y+1);
        }
        else
        {
            x=x+t-1,y=y+t+1;
            ll ans=0;
            while(x^y^1)
            {
                if(~x&1)ans+=s[x^1];
                if(y&1)ans+=s[y^1];
                x>>=1,y>>=1;
            }
            printf("%lld\n",ans);
        }
    }
}

日期: 2016-11-09

标签: BZOJ 线段树 暴力

这是一篇旧文,原始文章及评论可在 https://oldblog.mcfx.us/archives/70/ 查看。