HDU5828 區間開根加法求和 線段樹

2021-07-22 20:52:32 字數 2475 閱讀 2065

先需要想到乙個結論:

對於線段樹上的一塊,進行整體開根和加法(加法不影響結果)的次數越多,區間的最大值與最小值的差越小。

利用這個性質,我們維護一棵線段樹,線段樹上維護區間最大值、最小值、和、元素個數。

對於建樹、區間加法(修改)、區間查詢,寫法就是樸素的線段樹

對於區間開根:

1、若區間最大值和最小值的差為0,即整個區間的所有元素相等。此時開根相當於區間覆蓋同乙個值。

2、若區間最大值和最小值的差為1,那麼分為兩種情況(可以簡單地證明不會存在別的情況)

(1) sqrt( 最大值 ) - sqrt( 最小值 ) = 1 , 此時開根相當於區間減法。

(2) sqrt( 最大值 ) - sqrt ( 最小值) = 0 , 此時開根相當於區間覆蓋。

3、若區間最大值和最小值的差大於等於2,那麼繼續向下遞迴暴力修改合併。

tips:

1、3秒時間要跑100組資料,注意線段樹的常數。可以考慮讀入、輸出優化。

2、long long和開根的精度

3、若乙個線段樹結點的左兒子和右兒子被相同的樹區間覆蓋,此時需要將標記上傳,否則嚴重影響效率。

#include #include #include #include //#define mid (l + r) >> 1 

#define ls (t << 1)

#define rs ((t<<1) | 1)

#define n 100050

using namespace std;

typedef long long ll;

struct treetr[4*n];

ll a[n],tag[4*n],tag2[4*n];

ll n,m;

ll ans = 0ll;

inline void read(ll &x)

void out(ll a)

inline tree merge(tree p1,tree p2,int t) else tag2[t] = -1;

tmp.max = max( p1.max , p2.max );

tmp.min = min( p1.min , p2.min );

tmp.sum = p1.sum + p2.sum;

tmp.siz = p1.siz + p2.siz;

return tmp;

}void build(int l,int r,int t)

tag2[t] = -1;

int mid = (l + r) >> 1;

build(l,mid,ls);

build(mid+1,r,rs);

tr[t] = merge(tr[ls],tr[rs],t);

}inline void color(int t,ll v)

inline void color2(int t,ll v)

inline void push_down(int t) else

tag2[t] = -1; tag[t] = 0;

return ;

}ll ll,rr; ll v;

void update_sqrt(int l,int r,int t)

ll p1 = sqrt( tr[t].max );

ll p2 = sqrt( tr[t].min );

if (tr[t].max - tr[t].min == 1) else

return ;}}

push_down(t);

int mid = (l + r) >> 1;

if (ll <= mid) update_sqrt(l,mid,ls);

if (rr > mid) update_sqrt(mid+1,r,rs);

tr[t] = merge(tr[ls],tr[rs],t);

}void update_add(int l,int r,int t)

push_down(t);

int mid = (l + r) >> 1;

if (ll <= mid)

update_add(l,mid,ls);

if (rr > mid)

update_add(mid+1,r,rs);

tr[t] = merge(tr[ls],tr[rs],t);

}void query(int l,int r,int t)

push_down(t);

int mid = (l + r) >> 1;

if (ll <= mid) query(l,mid,ls);

if (rr > mid) query(mid+1,r,rs);

tr[t] = merge(tr[ls],tr[rs],t);

}int main()

case 2:

case 3:

assert(0);}}

}return 0;

}

hdu1968 區間更新 區間求和(線段樹)

這次是把某個區間全部更新為乙個值,而不是增加或減少。最後詢問一下區間總和。思路還是差不多的。在更新時,當我們將乙個節點所維護的區間更新後,可以用這個區間的長度 新的值,即 tree x sum tree x r tree x l 1 tree x data。在查詢或更新區間時,可以將tree x d...

Hdu4027 線段樹開根號區間求和

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

HDU 5700 區間交(線段樹)

problem description 小a有乙個含有n個非負整數的數列與m個區間。每個區間可以表示為li,ri。它想選擇其中k個區間,使得這些區間的交的那些位置所對應的數的和最大。例如樣例中,選擇 2,5 與 4,5 兩個區間就可以啦。input 多組測試資料 第一行三個數n,k,m 1 n 10...