码迷,mamicode.com
首页 > 其他好文 > 详细

【模板】线段树-单点修改,区间查询

时间:2019-09-17 23:01:35      阅读:222      评论:0      收藏:0      [点我收藏+]

标签:input   strong   namespace   ios   put   target   区间修改   表示   pre   

容易理解但是难打(又长又难调)------仅代表个人观点

(能别打就别打)

线段树是什么?

大概长这样?(表示区间1到6)

技术图片

线段树是一颗二叉树,是通过二分思想建立的一颗表示区间关系的树形结构。(总之记住它很好用就对了)

怎样建一颗线段树

大概思路:

二分+递归

没什么好讲的,具体看代码吧。。

//建树
struct node
{
  int a,b;
}tree[100001];

void make_tree(int p,int x,int y)//p为当前节点编号,x,y为区间的左右端点 
{
    tree[p].a=x;
    tree[p].b=y;
    if(x<y)
    {
        int mid=(x+y)/2;
        make_tree(p*2,x,mid);//左子树 
        make_tree(p*2+1,mid+1,y);//右子树 
    } 
}

表示区间[1,n]的线段树有多少个节点?

(不要看它看起来没什么用的样子,还是很重要的)

技术图片

还是开到4*n吧,保险。

线段树怎么用?

单点修改

大概思路:

二分+递归找点,修改

代码:

//单点修改 
void adds(int p,int x,int V)
{
    tree[p].v+=V;//在每一个含有x的区间的权值上加上V 
    if(tree[p].a==tree[p].b)
    return;
    if(x<=tree[p*2].b)
    adds(p*2,x,V);//如果x在当前区间的左儿子里 
    if(x>=tree[p*2+1].a)
    adds(p*2+1,x,V); //如果在右儿子里 
}

 

(看不懂的话下面有图)(这图不是我画的)

技术图片

区间查询

大概思路:

二分+递归,如果在[x,y]里就加上当前区间的权值,如果不在就不加。

代码:

//区间查询
int ans;
void find(int x,int y,int p)
{
    if(tree[p].a>=x&&tree[p].b<=y)//如果当前区间正好在[x,y]里面 
    {
        ans+=tree[p].v;
        return;
    }
    if(x<=tree[p*2].b)
    find(x,y,p*2);
    if(y>=tree[p*2+1].a)
    find(x,y,p*2+1);
    
} 

 

(上面的图有解说)

先来看道题:线段树区间修改+单点查询

冥想ing。。

AC代码:

#include<iostream>
#include<cstdio>
using namespace std;
//建树
struct node
{
  int a,b,v;
}tree[2000010];
int a[500010];
void make_tree(int p,int x,int y)//p为当前节点编号,x,y为区间的左右端点 ,v是权值 
{
    tree[p].a=x;
    tree[p].b=y;
    if(x<y)
    {
        int mid=(x+y)/2;
        make_tree(p*2,x,mid);//左子树 
        make_tree(p*2+1,mid+1,y);//右子树 
    } 
}
int input(int p)//储值 
{
    if(tree[p].a==tree[p].b)
    {
        tree[p].v=a[tree[p].a];
        return tree[p].v;
    }
    tree[p].v=input(p*2)+input(p*2+1);
    return tree[p].v;
}
//单点修改 
void adds(int p,int x,int V)
{
    tree[p].v+=V;//在每一个含有x的区间的权值上加上V 
    if(tree[p].a==tree[p].b)
    return;
    if(x<=tree[p*2].b)
    adds(p*2,x,V);//如果x在当前区间的左儿子里 
    if(x>=tree[p*2+1].a)
    adds(p*2+1,x,V); //如果在右儿子里 
}
//区间查询
int ans;
void find(int x,int y,int p)
{
    if(tree[p].a>=x&&tree[p].b<=y)//如果当前区间正好在[x,y]里面 
    {
        ans+=tree[p].v;
        return;
    }
    if(x<=tree[p*2].b)
    find(x,y,p*2);
    if(y>=tree[p*2+1].a)
    find(x,y,p*2+1);
    
} 
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    scanf("%d",&a[i]);
    make_tree(1,1,n);
    input(1);
    int A,B,C;
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&A);
        if(A==1)
        {
            scanf("%d%d",&B,&C);
            adds(1,B,C); 
        }
        else
        {
            ans=0;
            scanf("%d%d",&B,&C);
            find(B,C,1);
            printf("%d\n",ans);
        }
    }
    return 0;
} 

 

 

【模板】线段树-单点修改,区间查询

标签:input   strong   namespace   ios   put   target   区间修改   表示   pre   

原文地址:https://www.cnblogs.com/Daz-Os0619/p/11469694.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!