基础题之线段树小结(hdu-1754)
线段树是用来成段更新的,在众多的数据中更新与查找,一般用线段树。
使用线段树,一般分几个步骤,1.建树,2.更新,3.查找。
而一般较小的数据(hdu-1166:5万左右)和较大数据(hdu-1754:20万)不同在于有一个技巧的使用;就是在第一步建树上,一般我习惯于用一个数组来储存数据,然后建树,但对于本题较大数据来说,就超时了(时间是3s,优化之前超时,优化了以后是1s,读一个数据就要两秒多,无语。。。。),所以直接在建树的时候录入数据,是需要注意的地方。
输入:本题目包含多组测试,请处理到文件结束。
在每个测试的第一行,有两个正整数 N 和 M ( 0<N<=200000,0<M<5000 ),分别代表学生的数目和操作的数目。
学生ID编号分别从1编到N。
第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩。
接下来有M行。每一行有一个字符 C (只取'Q'或'U') ,和两个正整数A,B。
当C为'Q'的时候,表示这是一条询问操作,它询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。
当C为'U'的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。
输出:对于每一次询问操作,在一行里面输出最高成绩。
AC代码(C++):
#include<iostream> #include<cstdio> using namespace std; //int a[maxn];要求是N<200,000; const int maxn=200010; int sum[4*maxn]; //如果建线段树,一般建的树是4倍的数据; int n,m; void build(int u,int l,int r) { int a; if(l==r) { scanf("%d",&a);//在此处输入,不用再开储存数组了; sum[u]=a;//因为用的就是sum[maxn]数组; } else { int mid=(l+r)>>1;//就是找输入线段的中点; build(2*u,l,mid);//建左孩子; build(2*u+1,mid+1,r);//建右孩子; //得到的线段是包含右端点不包含左端点的; sum[u]=(sum[2*u]>sum[2*u+1])?sum[2*u]:sum[2*u+1]; //因为我们需要找本段的最大的点,所以令父亲节点为本段最大值; } } void up(int u,int l,int r,int flag,int num) //更新函数 { if(l==r)//此时就是搜索的最终节点的时候; { sum[u]=num; //本题要求直接更新,就直接赋值就行了; } else { int mid=(l+r)>>1;//同样的找中点; if(flag<=mid)up(2*u,l,mid,flag,num); //如果需要更换的点在左孩子;就在左孩子更新; else up(2*u+1,mid+1,r,flag,num);//否则就在右孩子更新; sum[u]=(sum[2*u]>sum[2*u+1])?sum[2*u]:sum[2*u+1]; //在更新最小节点后,把他的所有父亲节点都更新; } } int query(int u,int l,int r,int tl,int tr) //查找函数,功能实现的函数; { if(tl<=l&&tr>=r) //实际上就是找到要求的线段,也就是(tl==l&&tr==r); { return sum[u];//返回值,就是所求值; } else { int mid=(l+r)>>1;//还是找中点; if(tr<=mid)return query(2*u,l,mid,tl,tr); //如果所求线段右端小于中点,就是都在左孩子,在左孩子找; else if(tl>mid)return query(2*u+1,mid+1,r,tl,tr); //否则(所求线段都在中点右边)就在右孩子找; else//否则一半在左,一半在右,分开求,取其中较大值; { int t1=query(2*u,l,mid,tl,mid); int t2=query(2*u+1,mid+1,r,mid+1,tr); return (t1>t2)?t1:t2; } } } int main() { int l,r; while(scanf("%d%d",&n,&m)!=EOF) { build(1,1,n);//建树并输入数据; char ch; while(m--) { getchar(); scanf("%c%d%d",&ch,&l,&r); if(ch=='U')up(1,1,n,l,r);//更新; else if(ch=='Q') { printf("%d\n",query(1,1,n,l,r));//求值; } } } return 0; }

浙公网安备 33010602011771号