先需要想到乙個結論:
對於線段樹上的一塊,進行整體開根和加法(加法不影響結果)的次數越多,區間的最大值與最小值的差越小。
利用這個性質,我們維護一棵線段樹,線段樹上維護區間最大值、最小值、和、元素個數。
對於建樹、區間加法(修改)、區間查詢,寫法就是樸素的線段樹
對於區間開根:
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...