剛開始的時候第一反應這道題是成段的更新,不能乙個數乙個數的更新,那樣肯定會超時的!
但是再想了一會兒之後,發現成段更新比較困難,主要是這道題的每個節點的更新並不是統一的(也就是說並不是都加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次...