hdu 4027 Can you answer these queries? 线段树

题意:

给定n个数,有两种操作,0 a b操作时将[a,b]区间内的所有数都开根号并向下取整;1 a b操作时是求[a,b]区间内所有数的和。

题解:

由于开根号使得数值很快变为1,而1的时候开根号还是1可以跳过操作;所以我们用线段树维护区间的时候,碰到一段区间的和与这段区间长度相等时可以跳过以节约时间。

注意:m次操作中x>y的情况会出现,我被RE了无数次。





代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

typedef __int64 LL;
const int maxn=1e5+10;
struct node{
    int l,r;
    LL sum;
}e[maxn*4];
LL f[maxn];
void build(int a,int b,int c)
{
    if(a==b)
    {
        e[c].l=e[c].r=a;
        e[c].sum=f[a];
        return ;
    }
    int mid=(a+b)/2;
    build(a,mid,2*c);
    build(mid+1,b,2*c+1);
    e[c].l=a;
    e[c].r=b;
    e[c].sum=e[2*c].sum+e[2*c+1].sum;
}
void update(int a,int b,int c)
{
    if(e[c].sum==(LL)(e[c].r-e[c].l+1))return;
    if(e[c].l==e[c].r)
    {
        e[c].sum=(LL)sqrt(e[c].sum+0.5);
        return ;
    }
    int mid=(e[c].l+e[c].r)/2;
    if(b<=mid)update(a,b,2*c);
    else if(a>mid)update(a,b,2*c+1);
    else
    {
        update(a,mid,2*c);
        update(mid+1,b,2*c+1);
    }
    e[c].sum=e[2*c].sum+e[2*c+1].sum;
}
LL query(int a,int b,int c)
{
    if(e[c].l==a&&e[c].r==b)
    {
        return e[c].sum;
    }
    int mid=(e[c].l+e[c].r)/2;
    if(b<=mid)return query(a,b,2*c);
    else if(a>mid)return query(a,b,2*c+1);
    else return query(a,mid,2*c)+query(mid+1,b,2*c+1);
}
int main()
{
    int n,tt=0;
    while(scanf("%d",&n)!=EOF)
    {
        int i,j,k,m,a,b,c;
        for(i=1;i<=n;i++)scanf("%I64d",&f[i]);
        build(1,n,1);
        scanf("%d",&m);
        printf("Case #%d:\n",++tt);
        while(m--)
        {
            scanf("%d%d%d",&a,&b,&c);
            if(b>c)swap(b,c);
            if(a==0)update(b,c,1);
            else printf("%I64d\n",query(b,c,1));
        }
        printf("\n");
    }
    return 0;
}


你可能感兴趣的:(线段树)