HDU 4027 線段樹區間開根號

2021-09-08 21:06:37 字數 1953 閱讀 5409

這道線段樹的題目我並沒有按照線段樹的模板寫,這裡把要點講出來就行了。

第一:區間開根號不像區間乘或者除,能通過區間和然後一次性乘除求出乙個區間的乘除,所以區間開根號只能乙個乙個的開,但是如果乙個乙個的開不會超時嗎? 假設乙個數在long long的範圍裡面,也就是2^63這個範圍內,那麼對這個數開根號最多要開幾次? 63次。也就是說,開根號能夠在很少的次數內,讓乙個數一直趨近於乙個固定值1,這是區間開根號的乙個突破口,只要知道當前這個區間的值都等於或者小於1,那就不需要對這個區間做開根號的操作了。雖然乙個乙個的開根號看似很費時,但是事實上是可行的,我們假設有 10^5(題目n的上限)個數,每個數都是2^63,每次都對整個區間開根號我們需要花費多少時間,因為線段樹是乙個把陣列二叉樹化的結構,所以每次訪問乙個數,需要log(n)的時間複雜度,有n個數,並且每個數最多開log(2^63)次,那麼時間複雜度大約是 15*63*10^5;而且題目有說明,所有數的總和是不超過 2^63的,所以實際的時間複雜度還比上面說的要小很多;

所以具體的**要怎麼寫?

首先需要乙個記錄區間最大值的陣列,只要當前區間的最大值是小於或者等於1,那麼就不用繼續訪問下面的節點了,因為1開根號仍然是1,這能為我們省下不少時間,其次是乙個區間和的陣列。

每次區間修改,都需要遍歷到最底部的葉子節點,除非中途遇到區間最大值是小於或者等於1的就不用向下遍歷了,修改葉子節點的值,並且更新最大值,和記錄開根號後減少的值,在回溯的過程中更新區間最大值和區間和。

第二:這裡的資料有可能出現  x > y 的情況,所以要記得判斷,這是題目的乙個坑點;

下面是**,因為我沒有用線段樹的模板,所以重點在上面的敘述,最近在嘗試著脫離模板做題。

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

typedef long long ll;

const int maxn = 1e5+10;

const int inf = 0x3f3f3f3f;

ll a[maxn], maxn[4*maxn], sum[4*maxn]; // 把區間和和區間最大值設為全域性,在更新區間和和區間最值得時候

int l, r; // 通過訪問下標就能很容易的更新陣列

// 2*cur, 2*cur+1, cur/2,左右節點和父節點

ll init_max(int cur, int l, int r)

int mid = (l+r)/2;

maxn[cur] = max(init_max(cur*2, l, mid), init_max(cur*2+1, mid+1, r));

return maxn[cur];

}ll init_sum(int cur, int l, int r)

int mid = (l+r)/2;

sum[cur] = init_sum(cur*2, l, mid)+init_sum(cur*2+1, mid+1, r);

return sum[cur];

}void updata(int cur, int l, int r)

tmp = sum[cur];

int mid = (r+l)/2;

if (l <= mid) updata(cur*2, l, mid);

if (mid+1 <= r) updata(cur*2+1, mid+1, r);

maxn[cur] = max(maxn[cur*2], maxn[cur*2+1]); // 這裡更新區間最大值和區間和可以直接通過陣列下標得到

sum[cur/2] -= (tmp-sum[cur]);

}ll solve(int cur ,int l, int r)

int main (void)

else

}printf("\n");

}return 0;

}

Hdu4027 線段樹開根號區間求和

題意 給定100000個數,兩種操作,0 i j表示將i j這段的數字都開根號 向下取整 1 i j表示查詢i j之間的所有值的和 所有的和都不超過64位 思路 如果直接用線段樹更新會tle,此題的關鍵是要理解對任何64位以內的值,開根號最多不會超過7次,所以用線段樹做,更新到葉子節點的次數最多7次...

hdu 4027 線段樹區間開方求和

本來很早就做了這道題的,但是今天突然發現了.傳送門 解法 首先這道題的資料就告訴我們只能用線段樹,但區間操作似乎很蛋疼,我當時想的是用lazy標記記錄這段區間要開方幾次,等query時在統一進行單點更新,然後 我就t了,如果update一次query一次,我的lazy標記便並卵了,所以我們需要想更好...

HDU 4037 線段樹 區間開根號

區間開根號是不具備整體性的,即和開根號不一定等於開根號的和。但是由於由於在longlong範圍內的數開根號7次就會變成一所以我們單點更新也是可以的,剪枝就是如果乙個區間的和等於區間的大小就不用再繼續向下更新了,實現也簡單 ps 再注意幾個坑,每組樣例結束要多輸出乙個空行,and l,r的大小不確定 ...