刷题的时候偶尔会碰到一些区间查询 修改一类的题,这种问题大多可以用线段树解决,于是我稍微了解了一下线段树。其实线段树是很深奥的很有技巧性的数据结构,至今我只是很浅显很基本的了解了一点点。
因为Dalao们都已经讲得非常的详细,而且远远超出了蒟蒻的我的知识范围,所以在此我不再赘述。
大家看看这个吧:这个讲得很全面
下面我来举个栗子:
给出n个数,m个操作,每个操作分为两种:
操作1 修改第x数为y
操作2 询问区间[x,y]的元素和
解决:
读入n个数存储在d[]内
首先构造线段树
#define mid ((l+r)>>1) //即 (l+r)/2 位运算可以稍微提高效率
void build(int num,int l,int r)
{
if(l==r)
{
tree[num]=d[l];
return ;
}
else
{
int i=(num<<1); //即 num*2
build(i,l,mid);
build(i+1,mid+1,r);
tree[num]=tree[i]+tree[i+1]; //如果为查询最小值或最大值操作 则 tree[num]=max/*min*/(tree[i],tree[i+1]);
}
}
build(1,1,n);
然后每次读入操作类型以及x,y的值。
最后
修改操作void update(int num,int l,int r)
{
if(r<x||l>x) return ;
if(l==r&&l==x)
{
tree[num]=y;
return ;
}
else
{
int i=(num<<1);
update(i,l,mid);
update(i+1,mid+1,r);
tree[num]=tree[i]+tree[i+1];
}
}
update(1,1,n);
查询操作
int find(int num,int l,int r)
{
if(l>y||r<x) return 0;
if(r<=y&&l>=x) return tree[num];
int i=(num<<1);
return find(i,l,mid)+find(i+1,mid+1,r);
}
printf("%d\n",find(1,1,n));
最简单的模板大概就这样
练习题:1.Luogu P1531 I Hate It
3.Luogu U6724(某次比赛偶然做到的)
练习2:
#include<iostream>
#include<cstdio>
#define mid ((l+r)>>1)
using namespace std;
const int MAXN=100000+10;
int n,x,y,m;
int tree[MAXN*2];
char k[1];
int read()
{
int f=0,p=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') p=-1;c=getchar();}
while(c>='0'&&c<='9'){f=f*10+c-'0';c=getchar();}
return p*f;
}
void update(int num,int l,int r)
{
if(r<x||l>x) return ;
if(l==r&&l==x)
{
tree[num]+=y;
return ;
}
else
{
int i=(num<<1);
update(i,l,mid);
update(i+1,mid+1,r);
tree[num]=tree[i]+tree[i+1];
}
}
int find(int num,int l,int r)
{
if(r<x||l>y) return 0;
if(l>=x&&r<=y) return tree[num];
int i=(num<<1);
return find(i,l,mid)+find(i+1,mid+1,r);
}
int main()
{
n=read();m=read();
for(int i=1;i<=m;i++)
{
scanf("%s",&k[0]);
if(k[0]=='x')
{
x=read();y=read();
update(1,1,n);
}
else
{
x=read();y=read();
printf("%d\n",find(1,1,n));
}
}
return 0;
}
练习3:
#include<iostream>
#include<cstdio>
#define le i,l,((l+r)>>1)
#define ri i+1,(((l+r)>>1)+1),r
using namespace std;
const int MAXN=100000+5;
const int inf=2147483647;
int maxn,minn;
int d[MAXN];
int m,n,x,y;
char q[1];
struct tre
{
int maxn,minn;
}tree[MAXN*4];
int read()
{
int f=0;char c=getchar();
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9'){f=f*10+c-'0';c=getchar();}
return f;
}
void build(int num,int l,int r)
{
if(l==r)
{
tree[num].maxn=d[l];
tree[num].minn=tree[num].maxn;
return ;
}
else
{
int i=(num<<1);
build(le);
build(ri);
tree[num].maxn=max(tree[i].maxn,tree[i+1].maxn);
tree[num].minn=min(tree[i].minn,tree[i+1].minn);
}
}
void find(int num,int l,int r)
{
int i=(num<<1);
if(r<x||l>y) return ;
if(l>=x&&r<=y)
{
maxn=max(tree[num].maxn,maxn);
minn=min(tree[num].minn,minn);
return ;
}
find(le);
find(ri);
return ;
}
void update(int num,int l,int r)
{
int i=(num<<1);
if(l==r&&l==x)
{
tree[num].maxn=tree[num].minn=y;
return ;
}
else
{
if(r<x||l>x) return ;
update(le);
update(ri);
tree[num].maxn=max(tree[i].maxn,tree[i+1].maxn);
tree[num].minn=min(tree[i].minn,tree[i+1].minn);
}
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;i++)
d[i]=read();
build(1,1,n);
for(int i=1;i<=m;i++)
{
scanf("%s",&q);
if(q[0]=='Q')
{
x=read();y=read();
maxn=-1,minn=inf;
find(1,1,n);
printf("%d %d\n",maxn,minn);
continue;
}
else
{
x=read();y=read();
update(1,1,n);
continue;
}
}
return 0;
}
本蒟蒻水平低,只能讲到这里了,希望能帮到你。