以前只听说过线段树却并没有真正的写过
题目是中文的就不说了很明显是线段树的题,细节见代码的注释
貌似注释太多也不好看了,就再附上一个无注释的版本,哈哈。。
#include<algorithm> #include<cstdio> #define maxn 200005 struct point { int left,right,mavalue; }node[3*maxn];//这个树并没有记录左右儿子的位置,而是直根据二叉树u的左儿子为2*u 右儿子为2*n+1来生成的,但是是有点浪费空间的 int score[maxn];//记录初始时学生的分数 void buildtree(int left,int right,int u)//初始的构建树的函数 left 和right 分别为当前这棵树的区间范围,此树我用的是闭区间,一般是用半开办闭的区间,u是当前这棵树的根 { node[u].left=left;//给区间左端赋值 node[u].right=right;// 给区间右端赋值 if(left==right) node[u].mavalue=score[left]; //当区间长度为一时区间最大值即为其对应的一个分数的值 else//当区间的长度大于一时,递归构建子树 { buildtree(left,(left+right)/2,2*u); //递归构建左子树 buildtree(((left+right)/2)+1,right,2*u+1);//递归构建右子树 node[u].mavalue=std::max(node[2*u].mavalue,node[2*u+1].mavalue);//更新区间的最大值为左右子树的区间最大值的大的值 } }; void updata(int stu,int val,int u)//修改操作,修改某个学生的分数,亦要更新包含它的区间的最大值 { node[u].mavalue=std::max(val,node[u].mavalue);//更新当前这棵树的所包含的区间的最大值 if(node[u].left==node[u].right) return;//区间长度为1了说明修改完成了 if(stu<=node[2*u].right) updata(stu,val,2*u);//如果stu被包含在左树中就去修改左子树 else updata(stu,val,2*u+1);//反之修改右子树 } int query(int left,int right,int u)//查询操作,找到在在闭区间[left,right]内的最大值 { if(node[u].left==left&&node[u].right==right) return node[u].mavalue;//刚好找到了这个区间则这个区间的最大值即为答案 if(right<=node[2*u].right) return query(left,right,2*u);//在左子树中找到了包含这个区间的区间, if(left>=node[2*u+1].left) return query(left,right,2*u+1);//在右子树中找到了包含这个区间的区间,则去这个区间去找 //在没找到包含我们要查找的区间的区间时,就把我们把当前的区间二分,取二分区间的最大值为我们要的答案 int mid=(node[u].left+node[u].right)/2;//注意二分的是当前区间,而不是查找的区间。再根据二分出的中值把我们要查找的区间,分成2部分 return std::max(query(left,mid,2*u),query(mid+1,right,2*u+1));//把要查找的区间分成2部分后,再去左右子树中去分别去查找2部分区间的最大值 } int main() { int n,m,s,e;char temp,c; while(scanf("%d%c%d%c",&n,&temp,&m,&temp)!=EOF)//读入数据可能我这样读入有点奇葩,不过能AC就行 { for(int i=1;i<=n;i++) scanf("%d%c",&score[i],&temp); buildtree(1,n,1); for(int i=0;i<m;i++) { scanf("%c",&c); scanf("%c%d%c%d%c",&temp,&s,&temp,&e,&temp);//读入的时候要保证c读到的是字母而不是空格或回车 if(c=='U') updata(s,e,1); if(c=='Q') printf("%d\n",query(s,e,1)); } } return 0; }
其实由于第一次写代码大部分框架也是源于网络,但是在我完全弄懂了以后再修改,写注释的。。。。
#include<algorithm> #include<cstdio> #define maxn 200005 struct point { int left,right; int mavalue;//区间的最大值 }node[3*maxn]; int score[maxn]; void buildtree(int left,int right,int u) { node[u].left=left; node[u].right=right; if(left==right) node[u].mavalue=score[left]; else { buildtree(left,(left+right)/2,2*u); buildtree(((left+right)/2)+1,right,2*u+1); node[u].mavalue=std::max(node[2*u].mavalue,node[2*u+1].mavalue); } }; void updata(int stu,int val,int u) { node[u].mavalue=std::max(val,node[u].mavalue); if(node[u].left==node[u].right) return; if(stu<=node[2*u].right) updata(stu,val,2*u); else updata(stu,val,2*u+1); } int query(int left,int right,int u) { if(node[u].left==left&&node[u].right==right) return node[u].mavalue; if(right<=node[2*u].right) return query(left,right,2*u); if(left>=node[2*u+1].left) return query(left,right,2*u+1); int mid=(node[u].left+node[u].right)/2; return std::max(query(left,mid,2*u),query(mid+1,right,2*u+1)); } int main() { int n,m;char temp; while(scanf("%d%c%d%c",&n,&temp,&m,&temp)!=EOF) { for(int i=0;i<n;i++) scanf("%d%c",&score[i],&temp); char c;int s,e; buildtree(1,n,1); for(int i=0;i<m;i++) { scanf("%c%c%d%c%d%c",&c,&temp,&s,&temp,&e,&temp); if(c=='U') updata(s,e,1); if(c=='Q') printf("%d\n",query(s,e,1)); } } return 0; }