“线段树,也叫区间树,是一个完全二叉树,它在各个节点保存一条线段(即“子数组”),因而常用于解决数列维护问题,它基本能保证每个操作的复杂度为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; }