首页 > 代码库 > 简单线段树中的一系列题目
简单线段树中的一系列题目
1.HDU 1166 http://acm.hdu.edu.cn/showproblem.php?pid=1166
题目大意:
了解地方的兵营人数,每次询问告知区间内的总人数,其中会有兵营人数变更的更新操作
这里要用到求和的query:
int query(int x,int y)
{
int i=D+x-1,j=D+y+1,ans=0;
for(;i^j^1;i>>=1,j>>=1){
if(~i&1) ans+=tree[i^1];
if(j&1) ans+=tree[j^1];
}
return ans;
}
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 using namespace std; 6 7 #define N 50005 8 9 int a[N],tree[200010];10 int D;11 string s;12 13 void update(int x)14 {15 for(int i=x;i^1;i>>=1){16 tree[i>>1]=tree[i]+tree[i^1];17 }18 }19 20 int query(int x,int y)21 {22 int i=D+x-1,j=D+y+1,ans=0;23 for(;i^j^1;i>>=1,j>>=1){24 if(~i&1) ans+=tree[i^1];25 if(j&1) ans+=tree[j^1];26 }27 return ans;28 }29 int main()30 {31 int T,n,c,d;32 cin>>T;33 for(int i=1;i<=T;i++){34 D=1;35 memset(tree,0,sizeof(tree));36 scanf("%d",&n);37 for(int j=1;j<=n;j++) scanf("%d",&a[j]);38 while(D<n+2) D<<=1;39 for(int j=1;j<=n;j++) tree[D+j]=a[j];40 for(int j=D-1;j>=1;j--) tree[j]=tree[j<<1]+tree[j<<1|1];41 printf("Case %d:\n",i);42 while(cin>>s){43 if(s=="End") break;44 45 else if(s=="Add"){46 scanf("%d%d",&c,&d);47 tree[D+c]+=d;48 update(D+c);49 }50 else if(s=="Sub"){51 scanf("%d%d",&c,&d);52 tree[D+c]-=d;53 update(D+c);54 }55 else if(s=="Query"){56 scanf("%d%d",&c,&d);57 printf("%d\n",query(c,d));58 }59 }60 }61 return 0;62 }
2.HDU 1754 http://acm.hdu.edu.cn/showproblem.php?pid=1754
题目大意:
老师想要知道某段学生区间的最高分,中间涉及学生成绩的更新操作。
这里用到的是求最大值的query:
int query(int x,int y)
{
int i=D+x-1,j=D+y+1,ans=-1;
for(;i^j^1;i>>=1,j>>=1){
if(~i&1) ans=max(ans,tree[i^1]);
if(j&1) ans=max(ans,tree[j^1]);
}
return ans;
}
总代码如下:
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#define N 200010int a[N],tree[4*N],D;void init(){ D=1; memset(tree,-1,sizeof(tree));}void treeBuild(){ for(int i=D-1;i>=1;i--) tree[i]=max(tree[i<<1],tree[(i<<1)^1]);}void update(int i){ for(;i^1;i>>=1){ tree[i>>1]=max(tree[i],tree[i^1]); }}int query(int x,int y){ int i=D+x-1,j=D+y+1,ans=-1; for(;i^j^1;i>>=1,j>>=1){ if(~i&1) ans=max(ans,tree[i^1]); if(j&1) ans=max(ans,tree[j^1]); } return ans;}int main(){ int n,m,x,y; char c; while(scanf("%d%d",&n,&m)!=EOF){ init(); while(D<n+2) D<<=1; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); tree[D+i]=a[i]; } treeBuild(); for(int i=1;i<=m;i++) { cin>>c; if(c==‘U‘){ scanf("%d%d",&x,&y); tree[D+x]=y,update(D+x); } else if(c==‘Q‘){ scanf("%d%d",&x,&y); printf("%d\n",query(x,y)); } } } return 0;}
3.HDU 2795 http://acm.hdu.edu.cn/showproblem.php?pid=2795
题目大意:
不断将广告靠上,再靠左贴,问能够贴到的行数
这里我们在线段树上存储的是行的位置,用w[]数组存储每行还能存多少长度的广告
这里虽说高度能达到10^9,但是我们在规划线段树的长度时并不需要那么长,因为n最大为200000,我们规划线段树的底层取到的是min(n,h);
所以整棵树最大达到4*n即可
这里不断将能够达到最大值的位置放在树顶,
判断时不断往下,因为要贴广告时尽可能朝上,所以如果满足往左走,不满足往右走
query
int query(int k)
{
int t=1;
if(w[tree[t]]<k) return -1; while(t<D){ if(w[tree[t<<1]]>=k) t<<=1;
else t=t<<1|1;
}
return t-D;
}
总代码如下:
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#define N 200010int w[N],tree[4*N],D,h,m,n,x,Min;void update(int i){ for(;i^1;i>>=1) tree[i>>1]=w[tree[i]]>w[tree[i^1]]?tree[i]:tree[i^1];}int query(int k){ int t=1; if(w[tree[t]]<k) return -1; while(t<D){ if(w[tree[t<<1]]>=k) t<<=1; else t=t<<1|1; } return t-D;}int main(){ while(scanf("%d%d%d",&h,&m,&n)!=EOF){ Min=min(h,n); memset(tree,0,sizeof(tree)); w[0]=0; for(D=1;D<Min+2;D<<=1); for(int i=1;i<=Min;i++) w[i]=m,tree[D+i]=i; for(int i=D-1;i>=1;i--) tree[i]=w[tree[i<<1]]>w[tree[i<<1|1]]?tree[i<<1]:tree[i<<1|1]; for(int i=1;i<=n;i++){ scanf("%d",&x); int t=query(x); printf("%d\n",t); w[t]-=x,update(D+t); } } return 0;}