hdu4027 線段樹的lazy操作

2021-06-16 09:22:27 字數 1656 閱讀 4041

剛開始的時候第一反應這道題是成段的更新,不能乙個數乙個數的更新,那樣肯定會超時的!

但是再想了一會兒之後,發現成段更新比較困難,主要是這道題的每個節點的更新並不是統一的(也就是說並不是都加k,或者都減k之類的);

所以我們並不能像一般的成段更新那樣去更新。

再仔細觀察後,其實我們可以很容易的發現,乙個數k(k<=2^63-1)在經過最多6,7次的開平方根後,必然會變成1,而且當1的平方根也是1;

也就是說當乙個數為1的時候,我們沒有必要對它進行操作和更新;而且乙個很大的數僅僅經過6,7次就可以變成1;

所以到這裡我們因該就可以形成乙個解題的大體思路了:

每當我們要進行更新操作的時候,我們先判斷一下這個區間是否有必要進行更新(若全都是1就沒有更新的必要了);

判斷的方法很簡單:就是看該區間的長度和該區間內的總值是否相等;

當我們確認有必要進行更新的時候,我們就要多整個區間進行更新,當然在進行更新的時候,要不斷的儲存t[root].sum值;

接下來的就是很水很水的區間求和了!!

#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define ll __int64

using namespace std;

const int n=100010;

struct node

t[n*4];

ll data[n];

int n,q;

void up(int fa)

void down(int l,int r,int fa)

int ls=fa<<1;

int rs=fa<<1|1;

int mid=(t[fa].l+t[fa].r)/2;

down(l,mid,ls);

down(mid+1,r,rs);

up(fa);

}void built(int l,int r,int fa)

int mid=(l+r)/2;

built(l,mid,fa<<1);

built(mid+1,r,fa<<1|1);

up(fa);

}void update(int l,int r,int fa)

if(r<=mid)

update(l,r,ls);

else if(l>mid)

update(l,r,rs);

else

up(fa);

}ll query(int l,int r,int fa)

int main()

{ int t=1;

while(scanf("%d",&n)!=eof)

{for(int i=1; i<=n; i++)

scanf("%i64d",&data[i]);

built(1,n,1);

int a,b,c;

printf("case #%d:\n",t++);

cin>>q;

while(q--)

{scanf("%d%d%d",&a,&b,&c);

if(b>c)swap(b,c);

if(a)

cout<

hdu 4027 線段樹區間開方求和

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

HDU 4027 線段樹區間開根號

這道線段樹的題目我並沒有按照線段樹的模板寫,這裡把要點講出來就行了。第一 區間開根號不像區間乘或者除,能通過區間和然後一次性乘除求出乙個區間的乘除,所以區間開根號只能乙個乙個的開,但是如果乙個乙個的開不會超時嗎?假設乙個數在long long的範圍裡面,也就是2 63這個範圍內,那麼對這個數開根號最...

Hdu4027 線段樹開根號區間求和

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