hdu1166
尼玛,无力吐槽,搞了几个小时,没想到是输出Case 时出错
这种类型是线段树,关于线段树,线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。
对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度。
使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,因此有时需要离散化让空间压缩。参照这个图理解下
建树:
void build(int left,int right,int i) { int mid; b[i].left=left; b[i].right=right; if(left==right) { b[i].sum=a[left]; return ; } mid=(left+right)/2; build(left,mid,2*i); build(mid+1,right,2*i+1); b[i].sum=b[2*i].sum+b[2*i+1].sum; }
查找:
int Query(int left, int right,int i) { int mid; if(b[i].left==left && b[i].right ==right) return b[i].sum; mid=(b[i].left+b[i].right)/2; if(right<=mid) return Query(left,right,2*i); else if (left>mid ) return Query(left,right,2*i+1); else return Query(left,mid,2*i) + Query(mid+1,right,2*i+1); }
删除,增加:
void Add(int id,int num,int i) { if(b[i].left==b[i].right) { b[i].sum=b[i].sum+num; return ; } else { b[i].sum=b[i].sum+num; if(id<=b[i*2].right) Add(id,num,2*i); else Add(id,num,2*i+1); } }
所以,有了以上函数,这道题就不会超时了啊
#include <stdio.h> #include <string.h> int a[50010]; struct node { int left,right,sum; }b[150010]; void build(int left,int right,int i) { int mid; b[i].left=left; b[i].right=right; if(left==right) { b[i].sum=a[left]; return ; } mid=(left+right)/2; build(left,mid,2*i); build(mid+1,right,2*i+1); b[i].sum=b[2*i].sum+b[2*i+1].sum; } void Add(int id,int num,int i) { if(b[i].left==b[i].right) { b[i].sum=b[i].sum+num; return ; } else { b[i].sum=b[i].sum+num; if(id<=b[i*2].right) Add(id,num,2*i); else Add(id,num,2*i+1); } } int Query(int left, int right,int i) { int mid; if(b[i].left==left && b[i].right ==right) return b[i].sum; mid=(b[i].left+b[i].right)/2; if(right<=mid) return Query(left,right,2*i); else if (left>mid ) return Query(left,right,2*i+1); else return Query(left,mid,2*i) + Query(mid+1,right,2*i+1); } int main() { int Case; int n; char str[10]; scanf("%d",&Case); int id,num; int i; int k=1; while(Case--) { scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d",&a[i]); } build(1,n,1); printf("Case %d:\n",k++); while(1) { scanf("%s",str); if(strcmp(str,"End")==0) break; scanf("%d%d",&id,&num); if(strcmp(str,"Query")==0) { printf("%d\n",Query(id,num,1)); } if(strcmp(str,"Add")==0) { //scanf("%d%d",&id,&num); Add(id,num,1); } if(strcmp(str,"Sub")==0) { //scanf("%d%d",&id,&num); Add(id,-num,1); } } } return 0; }