线段树 建树 单点修改 点点/区间查询

线段树(sgement tree)是一种分治思想的二叉树结构,用于在区间上进行信息统计。与按照二进制位进行区间划分的树状数组相比,线段树是一种更加通用的结构:

  1. 线段树的每个节点都代表一个区间。
  2. 线段树具有唯一的根节点,代表的区间是整个统计范围,如[1,n]。
  3. 线段树的每个叶节点都代表一个长度为1的元区间,如[x,x]

线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。

使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,因此有时需要离散化让空间压缩。

在这片文章中,我先讲一下最基本的建树,单点修改,单点/区间查询

线段树是一种用空间换时间的算法开建树的数组时切记 一定要开4倍的数组

#include<bits/stdc++.h>
using namespace std;
const int maxn=10000+10;
int a[maxn],sum[maxn*4];     //四倍空间
inline int read(){     //快读,没啥特殊意思
	int s=0,w=1;
	char ch=getchar();
	while(ch<=‘0‘ || ch>‘9‘){if(ch==‘-‘)w=-1;ch=getchar();}
	while(ch>=‘0‘ && ch<=‘9‘){s=s*10+ch-48;ch=getchar();}
	return s*w;
}
inline void pushup(int root){ //这个节点的值是该节点的左节点加右节点的和
	sum[root] = sum[root<<1]+sum[root<<1|1];
}//乘2是该节点的左节点,再加1则是右节点
inline void build(int l,int r,int root){//建树
	if(l == r){
		sum[root] = a[l];
		return;
	}
	int mid = (l+r)>>1;
	build(l,mid,root<<1);
	build(mid+1,r,root<<1|1);
	pushup(root);
}
inline void update(int l,int r,int root,int num,int w){//更新
	if(l == r){
		sum[root] += w;
		return;
	}
	int mid = (l+r)>>1;
	if(num <= mid)update(l,mid,root<<1,num,w);
	if(num > mid)update(mid+1,r,root<<1|1,num,w);
	pushup(root);
}
inline int query(int l,int r,int root,int num){//查询
	if(l == r)return sum[root];
	int mid = (l+r)>>1;
	if(num <= mid)return query(l,mid,root<<1,num);
	if(num > mid)return query(mid+1,r,root<<1|1,num);
}
inline int query2(int root,int l,int r,int L,int R){//区间查询
    if(L <= l && r <= R)
        return sum[root];
    int mid = (l+r)>>1,tmp = 0;
    if(L <= mid)
        tmp += query2(root<<1,l,mid,L,R);
    if(mid < R)
        tmp += query2(root<<1|1,mid+1,r,L,R);
    return tmp;
}
int main(){
	int n;
	n = read();
	for(int i = 1;i <= n;i++)scanf("%d",&a[i]);
	build(1,n,1);
//	for(int i = 1;i <= n*2-1;i++)printf("%d%c",sum[i],i == n?‘\n‘:‘ ‘);
	for(int i = 1,op,x,y,L,R;i <= 10;i++){
		scanf("%d",&op);
		if(op == 1)scanf("%d%d",&x,&y),update(1,n,1,x,y);
		if(op == 2)scanf("%d",&x),printf("%d\n",query(1,n,1,x));
		if(op == 3)scanf("%d%d",&L,&R),printf("%d\n",query2(1,1,n,L,R));
	}
	return 0;
}

  

数组实现线段树建树,单点修改,区间/单点查询

如果单单只是区间查询就没必要pushdowm,用不着

结构体的就懒得打了

自己想去

原文地址:https://www.cnblogs.com/wangyifan124/p/10294427.html

时间: 2024-10-23 01:39:53

线段树 建树 单点修改 点点/区间查询的相关文章

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

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

poj3171 Cleaning Shifts【线段树(单点修改区间查询)】【DP】

Cleaning Shifts Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4422   Accepted: 1482 Description Farmer John's cows, pampered since birth, have reached new heights of fastidiousness. They now require their barn to be immaculate. Farmer

线段树(单点修改,区间求和,区间最大)

(一)线段树 1.E - Lost Cows N (2 <= N <= 8,000) cows have unique brands in the range 1..N. In a spectacular display of poor judgment, they visited the neighborhood 'watering hole' and drank a few too many beers before dinner. When it was time to line up

!POJ 2352 左下角星星-线段树-(单点更新,区间查询)

题意:直接坐标系中有n个星星,每个星星左下角的星星个数是它的价值,输出价值为0~n-1的星星个数. 分析: 这题就没有上面四道线段树的题裸了. 这题是怎么联系到区间,然后用线段树维护的呢? 因为题目要求输入的次序是按y第一关键字,x第二关键字升序输入,那么我们可以想到对于星星A(x,y),它左下角的星星一定在比他先输入的星星中,所以我们只需判断在比他先输入的星星的x2,如果x2<=x,那么星星A的价值+1.所以这题就转化为了求区间中的tot[0~x],也就是区间查询.每输入一个星星,先在原来的树

模板 - 数据结构 - 线段树(单点修改)

这里是以区间最大值为例,要修改成其他的运算,注意修改每个函数的运算以及query中返回的无关值. 这里的区间最大值设置的最小元素为-1(在query中表示与当前区间不相交的区间的结果). 注意因为调用的方式传入l与r是(1,n),所以这个线段树(包括a)其实是从1开始计数的. 最后,小心爆MAXM. const int MAXM=200000; int a[MAXM+5],st[(MAXM<<2)+5]; void build(int o,int l,int r){ if(l==r) st[o

【线段树(单点修改,区间求和)】HDU1166 - 敌军布阵

hdu1166 敌兵布阵,单点修改,区间求和. [ATTENTION]MAXN要开成节点数的4倍,开得不够会提示TLE. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define lson l,m,root<<1 5 #define rson m+1,r,root<<1|1 6 using namespace std; 7 const int MAXN=50000*

A - A Simple Problem with Integers (线段树的区间修改与区间查询)

You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval. Input The firs

HDU 1540 Tunnel Warfare(线段树,单点更新,区间查询)

Problem Description During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast areas of north China Plain. Generally speaking, villages connected by tunnels lay in a line. Except the two at the ends, every vill

线段树 :区间修改,区间查询

题目描述 思路 代码 #include <cstdio> #include <cstring> long long n, m; struct { long long at[1000005], arr[1000005 << 2], ad[1000005 << 2]; void build(int k, int l, int r) { if (l == r) { arr[k] = at[l]; return; } int mid = l + r >>