初学线段树

刷题的时候偶尔会碰到一些区间查询 修改一类的题,这种问题大多可以用线段树解决,于是我稍微了解了一下线段树。其实线段树是很深奥的很有技巧性的数据结构,至今我只是很浅显很基本的了解了一点点。

因为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 

               2.Luogu P2068 统计和

               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;  
}


本蒟蒻水平低,只能讲到这里了,希望能帮到你。


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值