模板整合
一、树状数组
1.简介
树状数组,支持区间查询和区间修改
2.使用方法
声明 :binary_tree 对象名称
node :树状数组的数据类型
SIZE :数据范围
build(初始数组,数组长度) :初始化操作,为元素赋初值
update(left,right,value) :将 \([left,right]\) 内的元素都增加 \(value\)
query(left,right) :求 \([left,right]\) 区间内的元素和
3.代码
class binary_tree
{
#define node long long
#define SIZE 100000
public:
inline node query(int x,int y) {return (y+1)*sum(tree1,y)-sum(tree2,y)-x*sum(tree1,x-1)+sum(tree2,x-1);}
inline void build(node a[],int n)
{
tot=n; memset(tree1,0,sizeof(tree1)); memset(tree2,0,sizeof(tree2));
for(register int i=1;i<=tot;i++) modify(i,a[i]-a[i-1]);
}
inline void update(node x,node y,node k) {modify(x,k); modify(y+1,-k);}
private:
node tree1[SIZE+1],tree2[SIZE+1],tot;
inline node lowbit(node x) {return x&(-x);}
inline node sum(node a[],node x) {node ans=0; while(x>0) {ans+=a[x]; x-=lowbit(x);} return ans;}
inline void modify(node x,node k) {for(register node i=x;i<=tot;i+=lowbit(i)) {tree1[i]+=k; tree2[i]+=k*x;}}
#undef node
#undef SIZE
};
二、静态主席树
1.简介
主席树,支持查询区间第\(k\)大
2.使用方法
声明 :president_tree 对象名称
node :树状数组的数据类型
SIZE :数据范围
build(初始数组,数组长度) :初始化操作,将数组进行离散化,为元素赋初值
query(left,right,rank) :求 \([left,right]\) 区间内的第\(rank\)大
3.代码
class president_tree
{
#define node int
#define mid ((l+r)>>1)
#define fm(x) memset(x,0,sizeof(x))
#define SIZE 200000
public:
node query(int x,int y,int w) {return rank[_query(root[x-1],root[y],1,_size,w)];}
void build(int a[],int n)
{
tot=0; fm(rank); fm(root); fm(sum); fm(L); fm(R);
for(register int i=1;i<=n;i++) rank[i]=a[i];
sort(rank+1,rank+n+1);
_size=unique(rank+1,rank+n+1)-rank-1;
root[0]=_build(1,_size);
for(register int i=1;i<=n;i++)
root[i]=update(root[i-1],1,_size,lower_bound(rank+1,rank+_size+1,a[i])-rank);
}
private:
int tot,_size;
node rank[SIZE+1],root[SIZE+1],sum[(SIZE<<5)+1],L[(SIZE<<5)+1],R[(SIZE<<5)+1];;
node _build(int l,int r)
{
int k=++tot; sum[k]=0;
if(l<r)
{
L[k]=_build(l,mid);
R[k]=_build(mid+1,r);
}
return k;
}
node update(int pre,int l,int r,int w)
{
int k=++tot; L[k]=L[pre]; R[k]=R[pre]; sum[k]=sum[pre]+1;
if(l<r)
if(w<=mid) L[k]=update(L[pre],l,mid,w);
else R[k]=update(R[pre],mid+1,r,w);
return k;
}
node _query(int u,int v,int l,int r,int k)
{
if(l>=r) return l;
int w=sum[L[v]]-sum[L[u]];
if(w>=k) return _query(L[u],L[v],l,mid,k);
else return _query(R[u],R[v],mid+1,r,k-w);
}
#undef node
#undef mid
#undef fm
#undef SIZE
};
三、线段树
1.简介
线段树,支持区间修改和区间查询区间和
2.使用方法
声明 :segment_tree 对象名称
node :树状数组的数据类型
SIZE :数据范围
build(初始数组,数组长度) :初始化操作,为元素赋初值
update(left,right,value) :将 \([left,right]\) 内的元素都增加 \(value\)
query(left,right) :求 \([left,right]\) 区间内的元素和
3.代码
class segment_tree
{
#define SIZE 100010
#define node long long
#define ls k<<1
#define rs k<<1 | 1
#define mid ((l+r)>>1)
public:
void build(int a[],int n) {_build(a,1,1,n); tot=n;}
void update(int x,int y,int k) {_update(1,1,tot,x,y,k);}
node query(int x,int y) {return _query(1,1,tot,x,y);}
void clear() {tot=0; memset(sum,0,sizeof(sum)); memset(v,0,sizeof(v));}
private:
node sum[(SIZE<<2)+1],v[(SIZE)<<2+1]; int tot;
void pushup(int k) {sum[k]=sum[ls]+sum[rs];}
void pushdown(int k,int l,int r)
{
v[ls]+=v[k]; v[rs]+=v[k];
sum[ls]+=(mid-l+1)*v[k];
sum[rs]+=(r-mid)*v[k];
v[k]=0;
}
void _update(int k,int l,int r,int ql,int qr,int u)
{
if(ql<=l && r<=qr)
{
sum[k]+=u*(r-l+1);
v[k]+=u; return;
}
if(v[k]) pushdown(k,l,r);
if(ql<=mid) _update(ls,l,mid,ql,qr,u);
if(qr>mid) _update(rs,mid+1,r,ql,qr,u);
pushup(k);
}
node _query(int k,int l,int r,int ql,int qr)
{
if(ql<=l && r<=qr) return sum[k];
long long ans=0;
if(v[k]) pushdown(k,l,r);
if(ql<=mid) ans+=_query(ls,l,mid,ql,qr);
if(qr>mid) ans+=_query(rs,mid+1,r,ql,qr);
return ans;
}
void _build(int a[],int k,int l,int r)
{
if(l==r) {sum[k]=a[l]; return;}
_build(a,ls,l,mid); _build(a,rs,mid+1,r);
pushup(k);
}
#undef SIZE
#undef node
#undef ls
#undef rs
#undef mid
};