经过上次线段树的基本讲解,这次我们就专门来看几道例题。
---------------------------------------------------------------------------------------------------------
问题 D(1911): 【高级数据结构】线段的条数
题目描述
无限长的X轴上从下向上依次叠放一定长度某种线段。问在某个单位区间上一共叠放了多少条线段?
输入
第1行:1个整数N。1<=N<=100000,表示线段的条数
接下来N行,每行2个整数L,R,-100000 <=L < R<= 100000,表示一线段的左、右端点(左闭右开区间);
最后1行:1个整数P,表示单位区间的起点。-100000 <=P<100000
输出
第1行:1个整数M,表示[P, P+1) ]区间叠放了多少条线段
样例输入
5
-1 5
3 10
-7 7
3 4
-9 2
-4
样例输出
2
分析
void insert(int k,int l,int r){//插入算法
if(r<tree[k].l||tree[k].r<l) return;
if(l<=tree[k].l&&tree[k].r<=r){
tree[k].cnt++;
return;
}
insert(k*2,l,r);
insert(k*2+1,l,r);
}
/**********************************************/
void find(int k,int l,int r){//统计算法
if(r<tree[k].l||tree[k].r<l) return;
ans+=tree[k].cnt;
find(k*2,l,r);
find(k*2+1,l,r);
}
#include<cstdio>
#include<iostream>
using namespace std;
const int maxn=200001;
struct node{
int l,r;
int cnt;
}tree[maxn*4];
int N,P;
int ans;
void build(int k,int l,int r){
tree[k].l=l;
tree[k].r=r;
if (l==r) return;
int mid=(l+r)>>1;
build(k*2,l,mid);
build(k*2+1,mid+1,r);
}
void insert(int k,int l,int r){
if(r<tree[k].l||tree[k].r<l) return;
if(l<=tree[k].l&&tree[k].r<=r){
tree[k].cnt++;
return;
}
insert(k*2,l,r);
insert(k*2+1,l,r);
}
void find(int k,int l,int r){
if(r<tree[k].l||tree[k].r<l) return;
ans+=tree[k].cnt;
find(k*2,l,r);
find(k*2+1,l,r);
}
int main()
{
int add=100000;
build(1,0,200000);
scanf("%d",&N);
int L,R;
for(int i=1;i<=N;i++){
scanf("%d%d",&L,&R);
L+=add;R+=add;
insert(1,L,R-1);
}
scanf("%d",&P);
P+=add;
find(1,P,P);
printf("%d",ans);
}
问题 E(1910): 【高级数据结构】子区间的和
题目描述
一行N个方格,开始每个格子里的数都是0。现在动态地提出一些问题和修改:提问的形式是求某一个特定的子区间[A,B]中所有元素的和;修改的规则是指定一个位置X,将该元素都加上一个特定的值A(A可能为负)。
现在要求你能对每个提问作出正确的回答。
输入
第1行:2个整数N(1<=N<=1000000),Q(1<=Q<=60000),N表示格子的数量,编号从1..N。Q表示询问和修改的总数。
接下来Q行,每行的格式为:3个整数P ,A,B。第1个数P(0<=P<=1),表示操作类型。当P=0时,表示将编号为A的格子加上数B。当P=1时,表示询问区间[A,B]之间的和。
输出
若干行,依次输出每个询问操作的结果,每个询问占一行。
样例输入
1 4
0 1 100
1 1 1
0 1 -100
1 1 1
样例输出
100
0
分析
用线段树解
void modify(int p, int delta)//插入算法
//p表示要修改的元素x在线段树中的位置
{
do {
tree[p].sum += delta;
p /= 2;
}while(p > 0);
}
/*
要预处理出存每个元素在线段树的叶节点(单位区间)的位置。
对于查询次数非常多的题目,这样预处理是有价值的。
*/
/**********************************************/
void count(int i,int l,int r)//统计算法
{
if (r<tree[i].l || tree[i].r<l) return;
if (l<=tree[i].l && tree[i].r<=r)
{
ans+=tree[i].sum;
return;
}
count(i*2,l,r);
count(i*2+1,l,r);
}
#include<cstdio>
#include<cstring>
#define lowbit(x) ((x)&(-x))
int tree[1000005],N,T,Q;
void update(int pos,int val){
while(pos<=N){
tree[pos]+=val;
pos+=lowbit(pos);
}
}
int getsum(int x){
int sum=0;
while(x>0){
sum+=tree[x];
x-=lowbit(x);
}
return sum;
}
int main()
{
int x;
scanf("%d%d",&N,&Q);
while(Q--){
int p,a,b;
scanf("%d%d%d",&p,&a,&b);
if(!p) update(a,b);
if(p) printf("%d\n",getsum(b)-getsum(a-1));
}
}
---------------------------------------------------------------------------------------------------------
问题 F(1909): 【高级数据结构】二维区间的和
题目描述
输入
输出
对每一个指令字为2的输入,在一行上回答一个询问
样例输入
(如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)
0 4
1 1 2 3
2 0 0 2 2
1 1 1 2
1 1 2 -1
2 1 1 2 3
3
样例输出
3
4
提示
#include<cstdio>
#include<cstring>
#define lowbit(x) (x&-x)
#define MAXN 1029
int bittree[MAXN][MAXN];
int op,s,x1,y1,x2,y2,a;
void update(int posx,int posy,int val){
for(int i=posx;i<=s;i=i+lowbit(i))
for(int j=posy;j<=s;j=j+lowbit(j))
bittree[i][j]+=val;
}
int getsum(int posx,int posy){
int sum=0;
for(int i=posx;i>0;i=i-lowbit(i))
for(int j=posy;j>0;j=j-lowbit(j))
sum+=bittree[i][j];
return sum;
}
int main()
{
int p;
while(~scanf("%d",&p)){
if(p==3) return 0;
else if(p==1){
int x,y,a;
scanf("%d%d%d",&x,&y,&a);
update(x+1,y+1,a);
}
else if(p==2){
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
x1++,y1++,x2++,y2++;
printf("%d\n",getsum(x2,y2)-getsum(x1-1,y2)-getsum(x2,y1-1)+getsum(x1-1,y1-1));
}
else if(p==0) scanf("%d",&s);
}
}