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

Can you answer these queries?

A lot of battleships of evil are arranged in a line before the battle. Our commander decides to use our secret weapon to eliminate the battleships. Each of the battleships can be marked a value of endurance. For every attack of our secret weapon, it could decrease the endurance of a consecutive part of battleships by make their endurance to the square root of it original value of endurance. During the series of attack of our secret weapon, the commander wants to evaluate the effect of the weapon, so he asks you for help. 
You are asked to answer the queries that the sum of the endurance of a consecutive part of the battleship line. 

Notice that the square root operation should be rounded down to integer.

Input

The input contains several test cases, terminated by EOF. 
  For each test case, the first line contains a single integer N, denoting there are N battleships of evil in a line. (1 <= N <= 100000) 
  The second line contains N integers Ei, indicating the endurance value of each battleship from the beginning of the line to the end. You can assume that the sum of all endurance value is less than 2 63. 
  The next line contains an integer M, denoting the number of actions and queries. (1 <= M <= 100000) 
  For the following M lines, each line contains three integers T, X and Y. The T=0 denoting the action of the secret weapon, which will decrease the endurance value of the battleships between the X-th and Y-th battleship, inclusive. The T=1 denoting the query of the commander which ask for the sum of the endurance value of the battleship between X-th and Y-th, inclusive. 

Output

For each test case, print the case number at the first line. Then print one line for each query. And remember follow a blank line after each test case.

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

Case #1:
19
7
6

題意:

給一個序列,有倆種操作,一種是求區間和,一種是將區間每個數開根號後向下取整。  就是一道線段數的題。
坑點:

1.注意:Case #1:有個冒號
2.資料是long long,如果是int會TLE,因為超出int,就是負數,你所有的優化都會失效。
3.注意輸入和輸出都要用%lld
4.最重要的是他給的區間l和r,l可能會大於r,那麼就要先交換位置,最坑的一點,沒有之一。

解題思路:

就是一個線段樹,但是是開根號,沒有辦法用延遲更新,但是取根號在6,7次就會到1.
那麼我們模擬區間更新,如果父節點的權值和r-l+1相等,那麼就不用忘下更新了。因為都是1
具體看程式碼

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <math.h>
using namespace std;
int n,m;
long long tree[100010*4];
long long a[100000+10];
void PushUp(int rt){
    tree[rt] = tree[rt*2] + tree[rt*2+1]; ///區間和的更新操作
}

void Build(int l,int r,int rt){
    // l,r 代表的是這個區間內的左端點 和 右端點, rt代表的是 [l,r] 這個區間內的值是存在哪一個位置的。
    if(l==r){
        //scanf("%d",&tree[rt]);
         tree[rt] = a[l];
        return;
    }
    int m=(l+r)/2;// 對於區間區分,我們一般將m點劃入左半邊區間
    Build(l,m,rt*2);
    Build(m+1,r,rt*2+1);
    PushUp(rt); // PushUp 函式是通過2個子節點來更新現在這個節點的狀態, 對於不同的要求需要不同的寫法。

}
long long Query(int l,int r,int rt,int L,int R){// [L,R]為查詢區間
    if(L<=l&&r<=R){
        return tree[rt];// 如果成立則滿足查詢區間覆蓋了當前區間, 直接返回當前區間的值
    }
    int m=(l+r)/2;
    long long res=0;
    if(L<=m)    res+=Query(l,m,rt*2,L,R);//左邊有一部分需要查詢的區域。
    if(m<R)     res+=Query(m+1,r,rt*2+1,L,R);//右邊有一部分。
    return res;

}
void Updata(int l,int r,int rt,int L,int R){// l,r,rt 與前面的定義一樣, L代表的是要更新區間的位置,C代表的是修改後的值

    if(L<= l && r <= R && tree[rt] == (long long)(r-l+1))
    {
        return ;
    }
    if(l==r){// 這裡不能寫成 if(l == L) 因為有可能左端點恰好是要更新的位置, 但是還有右端點, 我們直接更新的只有區間 [L,L]。
        tree[rt]=(long long )sqrt(1.0*tree[rt]);
        return ;
    }
    int m=(l+r)/2;
    if(L<=m) Updata(l,m,rt*2,L,R);//要更新的區間在左邊部分,所以往左邊走,更新左邊
    if(m<R) Updata(m+1,r,rt*2+1,L,R);//要更新的區間在右邊部分, 往右邊走,更新右邊
    PushUp(rt);//更新完子節點之後需要更新現在的位置, 需要保證線段樹的性質。
}
int main()
{

    int cnt=1;
    while(scanf("%d",&n)!=EOF){

        for(int i = 1; i <= n; i++)
            scanf("%lld", &a[i]);
        Build(1,n,1);
        int x,y,t;
        printf("Case #%d:\n",cnt++);
        scanf("%d", &m);
        while(m--){

            scanf("%d%d%d",&t,&x,&y);
            if(x>y){
                int temp=x;
                x=y;
                y=temp;
            }
            if(t==0){

                    Updata(1,n,1,x,y);
            }
            if(t==1){
                cout << Query(1,n,1,x,y) << endl;
            }

        }
        cout << endl;
    }
    //cout << "Hello world!" << endl;
    return 0;
}