1. 程式人生 > >Can you answer these queries? HDU

Can you answer these queries? HDU

題意

給定n個數,分別代表每一個戰艦的耐力值。有m個操作,當 t=1時,輸出x~y的戰艦耐力值之和,當 t=0時,使x~y戰艦的每一個耐力值都變為原來的平方根(向下取整)。

思路

遍歷 x到y 的每一個葉子節點,使他們的值變為原來的平方根,結果超時了。因為 1 的平方根還是 1,所以在更新時判斷這段區間的值是否都為1,如果都為1就不需要更新。

一開始以為會用到標記陣列,最後發現根本不許需要那麼麻煩。。。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=262144;
ll sum[maxn],node[maxn/2];
void pushup(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void bulid(int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]=node[l];
        return ;
    }
    int m=(l+r)>>1;
    bulid(l,m,rt<<1);
    bulid(m+1,r,rt<<1|1);
    pushup(rt);
}
void update(int L,int R,int l,int r,int rt)  //更新 L~R區間
{
    if(l==r)
    {
        sum[rt]=sqrt(sum[rt]);
        return ;
    }
    if(L<=l && R>=r && sum[rt]==r-l+1)  //優化  判斷區間的值是否都為1
        return ;
    int m=(l+r)>>1;
    if(L<=m)
        update(L,R,l,m,rt<<1);
    if(R>m)
        update(L,R,m+1,r,rt<<1|1);
    pushup(rt);
}
ll query(int L,int R,int l,int r,int rt)  // L~R區間求和
{
    if(L<=l && R>=r)
        return sum[rt];
    ll cnt=0;
    int m=(l+r)>>1;
    if(L<=m)
        cnt+=query(L,R,l,m,rt<<1);
    if(R>m)
        cnt+=query(L,R,m+1,r,rt<<1|1);
    return cnt;
}
int main()
{
    int n,m,k=1;
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)
            scanf("%lld",&node[i]);
        bulid(1,n,1);
        scanf("%d",&m);
        int x,y,z;
        printf("Case #%d:\n",k++);
        while(m--)
        {
            scanf("%d%d%d",&z,&x,&y);
            if(x>y)      //當 x>y時,交換兩點的值
                swap(x,y);
            if(z==1)
                printf("%lld\n",query(x,y,1,n,1));
            else
                update(x,y,1,n,1);
        }
        printf("\n");
    }
    return 0;
}