线段树
主要解决两个问题:(其他问题可以转化)更新某一点的值;求区间值;时间按复杂度(logn)
原数组a[1] a[2] …a[n];
写成树状数组c:c[x]=(x-lowbit(x),x] 左开右闭;
笔记
主要代码
const int N=?;
int tr[N];
int lowbit(int x){ return x&-x; }
void add(int x,int v){
for(int i = x;i < N; i += lowbit(i))
tr[i]+=v;
}
int sum(int x){
int res = 0;
for(int i = x;i > 0; i -= lowbit(i))
res+=tr[i];
return res;
}
线段树
两个基本操作:单点修改和区间查询。
四个核心函数:pushup:用子节点信息更新当前节点信息;build:在一段区间上初始化线段树;modify:单点修改;query:区间查询;
用数组存储线段树:x的父节点x>>1;x的左儿子:x<<1;x的右儿子x>>1|1.
核心代码:
const int N=100010;
int n,m;
int w[N];
struct Node{
int l,r;
int sum;
}tr[4*N];
void pushup(int u){
tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}
void build(int u,int l,int r){
if(l==r)
tr[u]={l,r,w[r]};
else {
tr[u]={l,r};
int mid=l+r >>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
pushup(u);
}
}
int query(int u,int l,int r){
if(tr[u].l>=l&&tr[u].r<=r) return tr[u].sum;
int sum=0;
int mid=tr[u].l+tr[u].r >>1;
if(l<=mid)
sum=query(u<<1,l,r);//因为是第一个书 sum初始值0 可以省略+
if(r>mid)
sum+=query(u<<1|1,l ,r );
return sum;
}
void modify(int u,int x,int v){
if(tr[u].l==tr[u].r)
tr[u].sum+=v;
else{
int mid=tr[u].l+tr[u].r >>1;
if(x<=mid)
modify(u<<1,x,v);
else
modify(u<<1|1,x,v);
pushup(u);
}
}