📑前言
本文主要是【线段树】——线段树简单使用的文章,如果有什么需要改进的地方还请大佬指出⛺️
🎬作者简介:大家好,我是听风与他🥇
☁️博客首页:CSDN主页听风与他
🌄每日一句:狠狠沉淀,顶峰相见
目录
- 📑前言
- [1-9]线段树图示
- 例题
- 📑文章末尾
[1-9]线段树图示
例题
1208.小球与盒子
package 难点攻克;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
/**
* 线段树一般需要四个函数,build(root,l,n)建树函数,modify(root,x,k)修改函数
* query(root,l,r)查询函数,pushup(root)更新函数
* 单点修改:修改某个点的值,区间查询,查询某个区间内的值(min,max,sum)
* 线段树比树状数组更强大
*
*/
public class 小球与盒子 {
static class node{
int l,r;
long v;
}
static node tree[];
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
StreamTokenizer sc = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
sc.nextToken();
int n = (int)sc.nval;
sc.nextToken();
int m = (int)sc.nval;
tree = new node[n*4];
build(1, 1, n);//建树
while(m-->0) {
sc.nextToken();
int op = (int)sc.nval;
sc.nextToken();
int x = (int)sc.nval;
sc.nextToken();
int y = (int)sc.nval;
if (op==1) {
modify(1, x, y);//单点修改,单点修改时是x加上y
}else {
System.out.println(query(1, x, y));//区间查询
}
}
}
//建树函数
public static void build(int u,int l,int r) {
tree[u] = new node();//申请空间
if (l == r) {//叶子节点
tree[u].l=l;
tree[u].r=r;
}else {
tree[u].l=l;
tree[u].r=r;
int mid = (l+r)/2;
build(2*u, l, mid);//递归左节点,建立左子树
build(2*u+1, mid + 1, r);//递归右节点,建立右子树
}
}
public static long query(int u,int l,int r) {
if(l <= tree[u].l && r>=tree[u].r) {
return tree[u].v;
}
long res = 0;
int mid = (tree[u].l + tree[u].r) / 2;
if(l <= mid) {
//往左边走,往右边走
res = query(u*2, l, r);
}
if(r > mid) {
res += query(u*2+1, l, r);
}
return res;
}
public static void modify(int u,int x,long k) {
if(tree[u].l == tree[u].r) {
tree[u].v += k;
}else {
int mid = (tree[u].l+tree[u].r)/2;
//遍历左右子树,进行单点修改的更新
if(x<=mid) {
modify(u*2, x, k);
}else {
modify(u*2+1, x, k);
}
push(u);//更新u
}
}
public static void push(int u) {
tree[u].v = tree[u*2].v + tree[u*2+1].v;
}
}