前言
首先,我们要知道线段树是干什么的?
线段树适合各种区间加法运算,如求区间和和求区间最值(不过如果不修改值的话还是用st表吧)。
线段树是一种很好的求区间加法的方法(比树状数组烦,但比树状数组好用)。
查询(logn),修改(logn)。
接下来就让我们来看看线段树如何构建吧。
建树
记住MAXN=4*N,自己画树去。
首先读一个x数组(废话)
然后就可以建树了,如果l==r的话就是没有儿子的节点(叶子),直接赋值为x[l];
然后左子树都在线段[l..mid]上(要不然干啥叫线段树),左儿子编号为root*2;
右子树都在线段[mid..r]上,右儿子编号为root*2+1;
最后更新tree的值(左子树与右子树的区间值,这里是区间和)
inline void build(int l,int r,int root)
{
if (l==r){tree[root]=x[l];return;}
int mid=(l+r)/2;
build(l,mid,root*2);
build(mid+1,r,root*2+1);
tree[root]=tree[root*2]+tree[root*2+1];
}
单点修改
x为修改的位置,ans为值,l和r为线段(树)区间。
如果最右端比查询位置左或最左端比查询位置右,就退出(废话真多)
如果查到了(为叶节点且是该位置)就修改此值。
最后递归然后更新值。
inline void updata(int l,int r,int root,int x,int ans)
{
if(r<x||l>x) return;
if(l==r&&l==x){tree[root]+=ans;return;}
int mid=(l+r)/2;
updata(l,mid,root*2,x,ans);
updata(mid+1,r,root*2+1,x,ans);
tree[root]=tree[root*2]+tree[root*2+1];
}
查询答案
inline long long search(int maxl,int maxr,int root,int l,int r) { if (maxl>r||maxr<l) return 0; if (l<=maxl&&maxr<=r) return tree[root]; int mid=(maxl+maxr)/2; return search(maxl,mid,root*2,l,r)+search(mid+1,maxr,root*2+1,l,r); }
区间修改
蒟蒻不会....
才怪
#include<bits/stdc++.h>
#define MAXN 1000005
using namespace std;
long long tree[4*MAXN],add[4*MAXN],n,num[MAXN],m;
inline void build(long long l,long long r,long long root)
{
if (l==r){tree[root]=num[l];return;}
long long mid=(l+r)/2;
build(l,mid,root*2);
build(mid+1,r,root*2+1);
tree[root]=tree[root*2]+tree[root*2+1];
}
inline void updata(long long l,long long r,long long root,long long x,long long ans)
{
if(r<x||l>x) return;
if(l==r&&l==x){tree[root]+=ans;return;}
long long mid=(l+r)/2;
updata(l,mid,root*2,x,ans);
updata(mid+1,r,root*2+1,x,ans);
tree[root]=tree[root*2]+tree[root*2+1];
}
inline void modify(long long root,long long maxl,long long maxr,long long l,long long r,long long v)
{
if (maxl>=l&&maxr<=r){add[root]+=v;return;}
tree[root]+=(min(maxr,r)-max(maxl,l)+1)*v;
long long mid=(maxl+maxr)/2;
if (l<=mid) modify(root*2,maxl,mid,l,r,v);
if (mid<r) modify(root*2+1,mid+1,maxr,l,r,v);
}
inline long long search(long long maxl,long long maxr,long long root,long long l,long long r)
{
if (maxl>r||maxr<l) return 0;
if (l<=maxl&&maxr<=r) return tree[root]+(maxr-maxl+1)*add[root];
long long mid=(maxl+maxr)/2;
long long res=(min(maxr,r)-max(maxl,l)+1)*add[root];
if (l<=mid) res+=search(maxl,mid,root*2,l,r);
if (mid<r) res+=search(mid+1,maxr,root*2+1,l,r);
return res;
}
int main()
{
scanf("%lld%lld",&n,&m);
for (long long i=1;i<=n;i++) scanf("%lld",&num[i]);
build(1,n,1);
for (long long i=1;i<=m;i++)
{
long long t,x,y,k;
scanf("%lld",&t);
if (t==1)
{
scanf("%lld%lld%lld",&x,&y,&k);
modify(1,1,n,x,y,k);
}
else
{
scanf("%lld%lld",&x,&y);
cout<<search(1,n,1,x,y)<<endl;
}
}
return 0;
}
返回下标
只放代码了~~~
就是加个结构体
#include<bits/stdc++.h>
using namespace std;
struct node{int id,minn;};
node tree[4*105];
int n,m,x[10005],wz;
inline void build(int l,int r,int root)
{
if (l==r){tree[root].minn=x[l];tree[root].id=l;return;}
int mid=(l+r)/2;
build(l,mid,root*2);
build(mid+1,r,root*2+1);
if (tree[root*2].minn>=tree[root*2+1].minn) tree[root].id=tree[root*2+1].id,tree[root].minn=tree[root*2+1].minn;
else tree[root].id=tree[root*2].id,tree[root].minn=tree[root*2].minn;
}
inline int search(int maxl,int maxr,int root,int l,int r)
{
if (maxl>r||maxr<l) return 0;
if (l<=maxl&&maxr<=r){wz=tree[root].id;return tree[root].minn;}
int mid=(maxl+maxr)/2;
return min(search(maxl,mid,root*2,l,r),search(mid+1,maxr,root*2+1,l,r));
}
inline void updata(int l,int r,int root,int x,int ans)
{
if(r<x||l>x) return;
if(l==r&&l==x){tree[root].minn+=ans;return;}
int mid=(l+r)/2;
updata(l,mid,root*2,x,ans);
updata(mid+1,r,root*2+1,x,ans);
if (tree[root*2].minn>=tree[root*2+1].minn) tree[root].id=tree[root*2+1].id,tree[root].minn=tree[root*2+1].minn;
else tree[root].id=tree[root*2].id,tree[root].minn=tree[root*2].minn;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&x[i]);
build(1,m,1);
cout<<search(1,m,1,1,m)<<endl;
cout<<wz<<endl;
return 0;
}