Can you answer these queries? (區間更新 開方操作)
阿新 • • 發佈:2019-02-15
H - Can you answer these queries?
ps:十分有趣的一道題目。一直在想如何用lazy標記,來使區間更新不超時間。
題意:
有n個數(1 <= n <= 100000),數最大為2^63。有m次操作(1 <= m <= 100000) ,操作有一下兩種:
- 使區間X到Y的所有數都開平方 (0)
- 輸出區間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 ; }