数据结构,线段树HDU1166
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h> #include<stdlib.h> #include<string.h> typedef struct CNode { int L,R; //区间起点和终点 int key;//兵力 int add;//这是记录增量 struct CNode * left, * right;//放置左右孩子指针 }IT; IT *creat(int l,int r)//建树,用二叉链做,压力。。 { IT *s=(IT *)malloc(sizeof(IT)); s->L=l; s->R=r; s->key=0; if(l==r)//左右相等,表示只有自己一个节点了 { s->left=s->right=NULL; s->key=0; return s; } else { s->left=creat(l,(r+l)/2);//没到底的话就继续往下开设节点 s->right=creat((r+l)/2+1,r);// s->key=s->left->key+s->right->key;// return s; } } void change(IT *T,int l,int r,int x) { int mid; if(T->L==l&&T->R==r)//左右相等,表示找到了 { T->key+=x*(r-l+1);//找到后将所有下设的增量都加到总和里 T->add=x;//保留增量,不往下加,这里可以节省时间 return ; } if(T->add) { if(T->left) T->left->add+=T->add; if(T->right) T->right->add+=T->add;//这里要加上去并且清0是因为之前没有往下加,这次或查询或更新,都要改成正确的值 T->add=0; } mid=(T->L+T->R)/2; if(r<=mid) { change(T->left,l,r,x);//如果右边区间小于中部,说明在左侧,更新左子树 } else if(l>mid) change(T->right,l,r,x);//同上 else { change(T->left,l,mid,x),change(T->right,mid+1,r,x);//同上 } T->key=T->left->key+T->right->key;//这里很重要,如果没这一句,叶子结点以上的根结点都没能得到更新 } int sum(IT *T,int l,int r)//求总和的算法跟更新的算法类似 { int mid=(T->L+T->R)/2; if(T->L==l&&T->R==r)// { return T->key; } if(T->add) { if(T->left) T->left+=T->add; if(T->right) T->right+=T->add; T->add=0; } if(r<=mid) return sum(T->left,l,r);// else if(l>mid) return sum(T->right,l,r);// else { return (sum(T->left,l,mid)+sum(T->right,mid+1,r));//之所以要返回,是为了统计总和 } } int main() { int i,n,l,r,x,y,t,f=1; char s[20]; IT *T; scanf("%d",&t); while(t--) { scanf("%d",&n); T=creat(1,n); for(i=1;i<=n;i++) { scanf("%d",&x); change(T,i,i,x);//边读入边更新,这里把更新当成插入了 } printf("Case %d:\n",f++); while(scanf("%s",s),strcmp(s,"End")) { scanf("%d%d",&x,&y); if(strcmp(s,"Add")==0) change(T,x,x,y); else if(strcmp(s,"Sub")==0) change(T,x,x,-y); else printf("%d\n",sum(T,x,y)); } } return 0; }
http://acm.hdu.edu.cn/showproblem.php?pid=1166
搞一下午的二叉链线段树,终于1A。。。。%>_<%
线段树操作在三点
一,建树:
在网上找不到二叉链的代码,难道我奇葩了sro orz
结构体里保存有本身信息,增量,左右区间,孩子节点等等,在建树过程中,没用到一次函数,表示要启用一个节点,所以要重新申请,在判断函数给的左右
区间是否相等后再进行操作,如果相等,表示找到要找的区间,赋值后返回,否则递归实现建树
二,更新:
在更新过程中,如果找到区间,就把增量,信息都赋予节点,否则将增量传与孩子节点的增量,记得相加,最后判断要找的区间往左往右,递归完成,
其中要注意的事情是每过一个节点,都要把沿途的所有节点的信息进行修改,这里指总和
三,查询:
查询过程其实跟更新过程类似,只是要简单的返回和而已