线段树
一.让你求最区间的区域和之类的其他(或者其他满足交换律的)
二.权值线段树。
1.就是用一个桶(数组)来装一个区间的数在出现的次数
添加
void add(int l, int r, int v, int x) {
if (l == r)f[v]++;//f[]用来存x出现的次数
else {
int mid = (l + r) / 2;
if (x <= mid)add(l, mid, v << 1, x);
else add(mid + 1, r, v << 1 | 1, x);
f[v] = f[v << 1] + f[v << 1 | 1];
}
}
返回区间【x,y】中的数出现的次数
int find(int l, int r, int v, int x, int y){
if (l == x && r == y) return f[v];
else{
int mid = (l + r) / 2;
if (y <= mid) return find(l, mid, v * 2, x, y);
else if (x > mid) return find(mid + 1, r, v * 2 + 1, x, y);
else return find(l, mid, v * 2, x, mid) + find(mid + 1, r, v * 2 + 1, mid + 1, y);
}
}
返回第k大的数
int kth(int l, int r, int v, int k) {
if (l == r)return l;
else {
int mid = (l + r) >> 1, s1 = f[v << 1], s2 = f[v << 1 | 1];
if (k <= s1)return kth(l, mid, v << 1, k);
else return kth(mid + 1, r, v << 1 | 1, k - s1);
}
}
返回第k小的数
int kth(int l,int r,int v,int k)
{
if(l==r) return l;
else
{
int mid=(l+r)/2,s1=f[v*2],s2=f[v*2+1];
if(k<=s2) return kth(mid+1,r,v*2+1,k); else return kth(l,mid,v*2,k-s2);
}
}
查询一个数出现的次数
int find(int l,int r,int v,int x)
{
if(l==r) return f[v];
else
{
int mid=(l+r)/2;
if(x<=mid) return find(l,mid,v*2,x); else return find(mid+1,r,v*2+1,x);
}
}