“線段樹,也叫區間樹,是一個完全二叉樹,它在各個節點儲存一條線段(即“子數組”),因而常用於解決數列維護問題,它基本能保證每個操作的複雜度為O(lgN)。”
“線段樹並不適合所有區間查詢情況,它的使用條件是“相鄰的區間的資訊可以被合并成兩個區間的並區間的資訊”。即問題是可以被分解解決的。”
摘自董的部落格,講的很好
HDU4027有一點不同的是,他的 區間更新操作 要做的是把每個數開平方根向下取整
代碼來自:http://blog.163.com/just_gogo/blog/static/191439065201181072049741/
#include<stdio.h>#include<math.h>typedef __int64 int64;const int maxn = 100010;int64 Mi[maxn];typedef struct{int left,right;int64 sum,len;}STNode;STNode node[maxn<<2];void build(int l,int r,int root){node[root].left = l;node[root].right = r;node[root].len = r-l+1;if(l==r){node[root].sum = Mi[l];return;}int m = (l+r) >> 1;build(l,m,root<<1);build(m+1,r,root<<1|1);node[root].sum = node[root<<1].sum + node[root<<1|1].sum;}void update(int l,int r,int root){if(node[root].left == node[root].right){node[root].sum = (int64)sqrt((double)node[root].sum);return;}if(node[root].left == l && node[root].right==r){if(node[root].len == node[root].sum) return;}int m = (node[root].left + node[root].right) >> 1;if(r <= m)update(l,r,root<<1);else if(l > m)update(l,r,root<<1|1);else {update(l,m,root<<1);update(m+1,r,root<<1|1);}node[root].sum = node[root<<1].sum + node[root<<1|1].sum;}int64 query(int l,int r,int root){if(node[root].left==l && node[root].right==r){return node[root].sum;}int m = (node[root].left+node[root].right) >> 1;if(r <= m)return query(l,r,root<<1);else if(l > m)return query(l,r,root<<1|1);else return query(l,m,root<<1)+query(m+1,r,root<<1|1);}void swap(int &a,int &b){int tmp=a; a=b; b=tmp;}int main(){int i,n,m,time=1;int op,a,b;while(~scanf("%d",&n)){printf("Case #%d:\n",time++);for(i=1;i<=n;i++){scanf("%I64d",&Mi[i]);}build(1,n,1);scanf("%d",&m);for(i=0;i<m;i++){scanf("%d%d%d",&op,&a,&b);if(a>b)swap(a,b);if(op==1)printf("%I64d\n",query(a,b,1));else update(a,b,1);}puts("");}return 0;}