线段树是一种极为重要的数据结构,能够解决许多动态区间问题,例如区间修改,单点修改,区间最值查询,区间求和等,可以说是我们必须要掌握的技能,模板题链接如下:https://www.luogu.com.cn/problem/P3372,附上代码实现:
import javafx.scene.chart.StackedAreaChart;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
/**
* 线段树能解决的问题:
* 1.区间查询
* 2.单点修改
* 3.区间修改
*/
public class 线段树模板 {
static int MAX;//假设区间长度为1~MAX
static int [] Add;//定义为区间长度的四倍
static int [] A;//存原数组的数据
static long [] sum;
static StreamTokenizer scan = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
public static void main(String[] args) throws IOException {
int n,m;
MAX=read();
m=read();
Add=new int[MAX<<2];
sum=new long[MAX<<2];
A=new int[MAX+1];
for (int i = 1; i <= MAX; i++) {
int x=read();
A[i]=x;
}
Build(1,MAX,1);
for (int i = 0; i < m; i++) {
int x1=read();
if(x1==1)
{
int x2=read();
int x3=read();
int x4=read();
UpdateAll(x2,x3,1,MAX,x4,1);
}
if(x1==2)
{
int x2=read();
int x3=read();
System.out.println(qurty(x2,x3,1,MAX,1));
}
}
}
//将子区间的数据整合
private static void PushUp(int id)
{
sum[id]=sum[id<<1]+sum[id<<1|1];
}
//初始建立树
private static void Build(int l,int r,int rt)
{
if(l==r)//到达了叶结点
{
sum[rt]=A[l];
return;
}
int m=(l+r)/2;
//左右递归
Build(l,m,rt<<1);
Build(m+1,r,rt<<1|1);
//合并子区间的信息
PushUp(rt);
}
//单点修改,这里以A[L]修改为C为例
private static void UpdateOne(int L,int C,int l,int r,int rt)
{
if(l==r)
{
sum[rt]+=C;
return;
}
int m=(r+l)>>1;
//选择合适的更新区间
if(L<=m) UpdateOne(L,C,l,m,rt<<1);
else UpdateOne(L,C,m+1,r,rt<<1|1);
//合并子区间
PushUp(rt);
}
//下推标记,第一次修改不会起到作用,只有后面涉及到更深的修改或查询时,将会释放懒标记
private static void PushDown(int rt,int ln,int rn)
{
if(Add[rt]>0)
{
//下推
Add[rt<<1]+=Add[rt];
Add[rt<<1|1]+=Add[rt];
//修改sum
sum[rt<<1]+=Add[rt]*ln;
sum[rt<<1|1]+=Add[rt]*rn;
//消除本节点标记
Add[rt]=0;
}
}
//区间修改
private static void UpdateAll(int L,int R,int l,int r,int k,int rt)
{
if(l>=L&&r<=R)
{
sum[rt]+=(r-l+1)*k;
Add[rt]+=k;
return;
}
int m=(l+r)/2;
PushDown(rt,m-l+1,r-m);
if(L<=m)UpdateAll(L,R,l,m,k,rt<<1);
if(m<R)UpdateAll(L,R,m+1,r,k,rt<<1|1);
PushUp(rt);
}
//区间查询
private static long qurty(int L,int R,int l,int r,int rt)
{
if(l>=L&&r<=R)
{
return sum[rt];
}
int m=(l+r)>>1;
//下推标记
PushDown(rt,m-l+1,r-m);
long ans=0;
if(L<=m) ans+=qurty(L,R,l,m,rt<<1);//递归左子区间
if(R>m) ans+=qurty(L,R,m+1,r,rt<<1|1);//递归右子区间
return ans;
}
private static int read() throws IOException {
scan.nextToken();
return (int)scan.nval;
}
}