前置细节
,得到
转二进制后,从右往左数第一个1与之前所有的0构成数
- 树状数组最终形成如上图结构
维护的是
的信息
,如
- 即到上层,包含当前区间的大区间
,如
- 即到同一层的前一个,与当前区间无关的另一同等大小的区间
的信息是由
整合的
- 如维护区间最大值,
- 用于解决将值变小且该值为区间最大值,或将值变大且该值为区间最小值
- 区间和不受影响原因求区间和不用管区间中某一点具体是多少
维护区间和
单点修改
void update(int x,int k) {
for(int i=x;i<=size;i+=lowbit(i)) {
tr[i]+=k;
}
}
区间修改
- 此时树状数组中维护的是差分数组
单点查询
- 若维护的不是差分数组,直接输出
- 若维护的是差分数组,则
,
为初值
int query(int x){ int res=0; for(int i=x;i>0;i-=lowbit(i)){ res+=t[i]; } return res; }
区间查询
- 若维护的不是差分数组
等于前缀和,
- 若维护的是差分数组,则
维护极值
以最大值为例
单点修改
void update(int x,int k) {
tr[x]=k;
for(int i=x;i<=size;i+=lowbit(i)) {//往上层接着更新
int lw=lowbit(i);
for(int j=1;j<lw;j<<=1) {
tr[i]=Math.max(tr[i], tr[i-j]);
//tr[8]=max tr[7],tr[6],tr[4],a[8]
//7=8-1.6=8-(10),4=8-(100)
}
}
}
区间查询
int query(int l,int r) {
//tr[i]=max [i-lowbit(i)+1,i]
//if l<=i-lowbit(i)+1 直接用tr[i]
//否则,只能用a[i],剩下递归l,i-1
if(l>r)return 0;
else if(l==r)return a[l];
else if(l<=r-lowbit(r)+1)//包含[l,r]=[r-lowbit(r)+1,r]=tr[r]
return Math.max(query(l, r-lowbit(r)),tr[r]);
else return Math.max(query(l, r-1), a[r]);
}
例:Atcoder Beginner Contest 339 E
题目大意
- 给定一个长度为
的序列a,
- 找到a的最长子序列,使得子序列中相邻两值的绝对差不超过
解题思路
- 定义
表示以
点为起点的最长子序列长度
- 从
号开始处理到
号,
- 直接暴力
过不去
- 考虑用树状数组维护区间最值
- 将
看作数组空间,查询区间即为
定义为以值
为起点的最长子序列长度
- 每处理完一个
,则添入树状数组中,保证处理当前第
个点,只有
的结果在数组里
import java.io.*;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;
import java.util.Vector;
public class Main{
static int[] a;
static int[] f;//对应长度
static
class BIT{
int size;
int[] tr;
public BIT(int n) {
size=n;
tr=new int[n+1];
}
int lowbit(int x) {
return x&(-x);
}
void update(int x,int k) {
//可能将当前区间最大值对应的点的值改小
tr[x]=f[x]=k;
for(int i=x;i<=size;i+=lowbit(i)) {
int lw=lowbit(i);
for(int j=1;j<lw;j<<=1) {
tr[i]=Math.max(tr[i], tr[i-j]);
//tr[8]=max tr[7],tr[6],tr[4],a[8]
//7=8-1.6=8-(10),4=8-(100)
}
}
}
int query(int l,int r) {
//tr[i]=max [i-lowbit(i)+1,i]
//if l<=i-lowbit(i)+1 直接用tr[i]
//否则,只能用a[i],剩下递归l,r-1
if(l>r)return 0;
else if(l==r)return f[l];
else if(l<=r-lowbit(r)+1)return Math.max(query(l, r-lowbit(r)),tr[r]);
else return Math.max(query(l, r-1), f[r]);
}
}
public static void main(String[] args) throws IOException{
AReader input=new AReader();
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
int n=input.nextInt();
int D=input.nextInt();
a=new int[n+1];
for(int i=0;i<n;++i) {
a[i]=input.nextInt();
}
BIT T=new BIT(500010);
f=new int[500010];
f[a[n-1]]=1;
T.update(a[n-1], 1);
for(int i=n-2;i>=0;--i) {
int l=a[i]-D<0?0:a[i]-D;
int r=a[i]+D>500000?500000:a[i]+D;
int t=T.query(l, r)+1;
f[a[i]]=t;
T.update(a[i], t);
}
int mx=T.query(0, 500001);
out.print(mx);
out.flush();
out.close();
}
static
class AReader{
BufferedReader bf;
StringTokenizer st;
BufferedWriter bw;
public AReader(){
bf=new BufferedReader(new InputStreamReader(System.in));
st=new StringTokenizer("");
bw=new BufferedWriter(new OutputStreamWriter(System.out));
}
public String nextLine() throws IOException{
return bf.readLine();
}
public String next() throws IOException{
while(!st.hasMoreTokens()){
st=new StringTokenizer(bf.readLine());
}
return st.nextToken();
}
public char nextChar() throws IOException{
//确定下一个token只有一个字符的时候再用
return next().charAt(0);
}
public int nextInt() throws IOException{
return Integer.parseInt(next());
}
public long nextLong() throws IOException{
return Long.parseLong(next());
}
public double nextDouble() throws IOException{
return Double.parseDouble(next());
}
public float nextFloat() throws IOException{
return Float.parseFloat(next());
}
public byte nextByte() throws IOException{
return Byte.parseByte(next());
}
public short nextShort() throws IOException{
return Short.parseShort(next());
}
public BigInteger nextBigInteger() throws IOException{
return new BigInteger(next());
}
public void println() throws IOException {
bw.newLine();
}
public void println(int[] arr) throws IOException{
for (int value : arr) {
bw.write(value + " ");
}
println();
}
public void println(int l, int r, int[] arr) throws IOException{
for (int i = l; i <= r; i ++) {
bw.write(arr[i] + " ");
}
println();
}
public void println(int a) throws IOException{
bw.write(String.valueOf(a));
bw.newLine();
}
public void print(int a) throws IOException{
bw.write(String.valueOf(a));
}
public void println(String a) throws IOException{
bw.write(a);
bw.newLine();
}
public void print(String a) throws IOException{
bw.write(a);
}
public void println(long a) throws IOException{
bw.write(String.valueOf(a));
bw.newLine();
}
public void print(long a) throws IOException{
bw.write(String.valueOf(a));
}
public void println(double a) throws IOException{
bw.write(String.valueOf(a));
bw.newLine();
}
public void print(double a) throws IOException{
bw.write(String.valueOf(a));
}
public void print(char a) throws IOException{
bw.write(String.valueOf(a));
}
public void println(char a) throws IOException{
bw.write(String.valueOf(a));
bw.newLine();
}
}
}
感谢这位大佬的博文启发https://blog.youkuaiyun.com/TheWayForDream/article/details/118436732