bzoj 3211: 花神游历各国

直接写题解吧。。。

题目这么长,其实就是2个操作:

1.询问L,R中的各个数之和

2.将L,R中的每个数x,将x修x1/2,向下取整。。

我们其实可以发现1000000000中的数修改不了几次就会变成1

那么直接暴力修改,若一段区间内的数全部<=1也就不用再改下去了。。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
#define p1 (p<<1)
#define p2 (p<<1|1)
const int N=100005;
int n,m,i,p,x,y,a[N],add[N<<2];
long long ans,t[N<<2];
void build(int l,int r,int p)
{
    if(l==r)
    {
        t[p]=a[l];
        if(a[l]<=1) add[p]=1;else add[p]=0;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,p1);
    build(mid+1,r,p2);
    t[p]=t[p1]+t[p2];
    add[p]=add[p1]&add[p2];
}
void update(int l,int r,int x,int y,int p)
{
    if(add[p]) return;
    if(l==r)
    {
        t[p]=(int)(sqrt(t[p]));
        if(t[p]<=1) add[p]=1;
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid) update(l,mid,x,y,p1);
    if(y>mid) update(mid+1,r,x,y,p2);
    add[p]=add[p1]&add[p2];
    t[p]=t[p1]+t[p2];
}
void solve(int l,int r,int x,int y,int p)
{
    if(x<=l&&r<=y)
    {
        ans+=t[p];
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid) solve(l,mid,x,y,p1);
    if(y>mid) solve(mid+1,r,x,y,p2);
}
int main()
{
    scanf("%d",&n);
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
    build(1,n,1);
    scanf("%d",&m);
    for(i=1;i<=m;i++)
    {
        scanf("%d%d%d",&p,&x,&y);
        if(p==1)
        {
            ans=0;
            solve(1,n,x,y,1);
            printf("%lld\n",ans);
        } else
        update(1,n,x,y,1);
    }
    return 0;
}

 

 

 

 

 

 
 
posted @ 2016-05-14 21:04  lwq12138  阅读(221)  评论(0编辑  收藏  举报