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

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

(能别打就别打)

线段树是什么?

大概长这样?(表示区间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;
} 

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

时间: 2024-10-09 13:28:33

【模板】线段树-单点修改,区间查询的相关文章

HDU 1754 I Hate It 【线段树单点修改 区间查询】

题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1754 I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 102825    Accepted Submission(s): 38669 Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,

HDU 3874 Necklace (线段树单点更新+区间查询+离线操作)

Problem Description Mery has a beautiful necklace. The necklace is made up of N magic balls. Each ball has a beautiful value. The balls with the same beautiful value look the same, so if two or more balls have the same beautiful value, we just count

hdu1698 Just a Hook(线段树+区间修改+区间查询+模板)

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 54923    Accepted Submission(s): 25566 Problem Description In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of

ZOJ 3632 Watermelon Full of Water(dp+线段树 单点修改)

题意: 一共有n天 每天西瓜售价为dp[i]元 该天的西瓜能吃v[i]天 而且这天如果买了西瓜之前的西瓜就要扔掉 问每天都吃到西瓜的最小花费是多少 思路: 从最后一天开始dp最小花费 并用线段树单点更新来维护 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <algorithm> using namespace std; #define ll long long #def

hdu1166 线段树单点修改与区间查询

基本上就是个简单的线段树的单点修改(update)与区间查询(query) 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1166 连Lazy标记都不用 附上代码 1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<algorithm> 5 using namespace std; 6 const int maxn=50000+1

HDU - 1166 敌兵布阵 (线段树+单点修改,区间查询和)

C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况.由于采取了某种先进的监测手段,所以每个工兵营地的人数C国都掌握的一清二楚,每个工兵营地的人数都有可能发生变动,可能增加或减少若干人手,但这些都逃不过C国的监视. 中央情报局要研究敌人究竟演习什么战术,所以Tidy要随时向Derek汇报某一段连续的工兵营地一共有多少人,例如Derek问:“Tidy,马上汇

CDOJ 1073 线段树 单点更新+区间查询 水题

H - 秋实大哥与线段树 Time Limit:1000MS     Memory Limit:65535KB     64bit IO Format:%lld & %llu Submit Status Practice UESTC 1073 Appoint description:  System Crawler  (2016-04-24) Description “学习本无底,前进莫徬徨.” 秋实大哥对一旁玩手机的学弟说道. 秋实大哥是一个爱学习的人,今天他刚刚学习了线段树这个数据结构. 为

敌兵布阵 HDU - 1166 (线段树单点修改)

敌兵布阵 HDU - 1166 题目链接:https://vjudge.net/problem/HDU-1166 题目: C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况.由于采取了某种先进的监测手段,所以每个工兵营地的人数C国都掌握的一清二楚,每个工兵营地的人数都有可能发生变动,可能增加或减少若干人手,但这些都逃不过C国的监视. 中央情报局要研究敌人

HDU1166(线段树单点更新区间查询)

敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 62483    Accepted Submission(s): 26386 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就