1. 程式人生 > >Can you answer these queries? (區間更新 開方操作)

Can you answer these queries? (區間更新 開方操作)

H - Can you answer these queries?

題目連結

ps:十分有趣的一道題目。一直在想如何用lazy標記,來使區間更新不超時間。

題意:

有n個數(1 <= n <= 100000),數最大為2^63。有m次操作(1 <= m <= 100000) ,操作有一下兩種:

  1. 使區間X到Y的所有數都開平方 (0)
  2. 輸出區間X到Y的所有數的和 (1)

輸入:

先輸入n(10)
輸入n(10)個數
輸入m(5)
輸入m(5)次操作 操作型別(0代表開方,1代表求值)以及X和Y代表區間的左右座標

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

輸出:

Case #1:
19
7
6

思路:

本題難在更新,在最開始時,對區間更新可以對區間內每一個點進行單點更新,但是複雜度極高。但是我們會發現即使是最大的2^63,在7次開方之後歸1,且1開平方也是1。所以我們可以用一個標記來對樹的節點進行標記。如果該節點範圍內所有樹都為1,則遇到開方操作可以無視。這樣一來,我們就找到了優化更新的方法

程式碼如下:

#include <stdio.h>
#include <cmath>
#include <string.h>
#include <algorithm>
using namespace std;

const int maxn = 1e5 + 10;

long long num[maxn];

struct Tree
{
    int lson , rson ;
    long long sum;
    bool is1;
}tree[maxn * 4];


void Push_one(int h)
{
    tree[h].is1 = tree[h << 1].is1 && tree[h << 1 | 1].is1;
}

void Build (int l , int  r ,int h)
{
    tree[h].lson = l;
    tree[h].rson = r;
    if (l == r)
    {
        if (num[l] == 1)
            tree[h].is1 = true;
        else
            tree[h].is1 = false;

        tree[h].sum = num[l];
        return;
    }
    int mid = (l + r) >> 1;
    Build (l , mid , h << 1) ;
    Build (mid + 1 , r , h << 1 | 1);
    tree[h].sum = tree[h << 1].sum + tree[h << 1 | 1].sum;
    Push_one(h);
}

void Update (int l , int r , int h)
{
    if (tree[h].is1)
        return ;
    if (tree[h].lson == tree[h].rson)
    {
        tree[h].sum = sqrt(tree[h].sum);
        if (tree[h].sum == 1)
            tree[h].is1 = true;
            return ;
    }
    int mid = (tree[h].lson + tree[h].rson ) >> 1;
    if (r <= mid)
        Update (l , r , h << 1 );
    else if (l > mid)
        Update (l , r , h << 1 | 1);
    else
    {
        Update ( l , mid , h << 1);
        Update ( mid + 1 , r , h << 1 | 1);
    }
    tree[h].sum = tree[h << 1].sum + tree[h << 1 | 1].sum;
    Push_one(h);
}

long long Query (int  l , int  r ,  int h)
{
    if (l == tree[h].lson && r == tree[h].rson)
    {
        return tree[h].sum;
    }
    int mid = (tree[h].lson + tree[h].rson) >> 1;
    if (mid < l)
        Query (l , r , h << 1 | 1);
    else if(mid >= r)
        Query (l , r , h << 1);
    else
        return Query (l , mid , h << 1) + Query (mid +1  , r , h << 1 | 1);

}

int main()
{
    int n;
    int test = 1;
    while (~scanf ("%d" , &n))
    {

        memset (tree , 0 , sizeof (tree));
        for (int i = 1 ; i <= n ; i++)
            scanf ("%lld" , &num[i]);
        Build (1 , n , 1);
        int m;
        scanf ("%d" , &m);
        int a , b , c;
        printf ("Case #%d:\n" , test);
        test++;
        while (m--)
        {
            scanf ("%d%d%d" , &a , &b , &c);
            if(b > c)
                swap(b , c);
            if (a)
                printf ("%lld\n" , Query (b , c , 1));
            else
                Update (b , c , 1);
        }
        printf("\n");
    }
    return 0 ;
}