树状数组
树状数组专题
1、树状数组区间求和,单点更新
2、树状数组区间更新,单点求值
3、树状数组求最值
1)HDU4521 小明序列
地址:http://acm.hdu.edu.cn/showproblem.php?pid=4521
题意:求给定序列中,求一个最长的序列元素个数,这个最长序列任意相邻的元素下标满足j - i > d
算法: 首先这题数据量比较大,O(N^2)的算法肯定无法过,所以时间复杂度应该是O(NlogN)左右。
所以需要数据结构来辅助, 线段树,或者树状数组
如果不加任何条件,此题应该是求最长上升子序列的~~
加了条件后,我们依然设dp[i]为以i结尾的数并且能满足条件的最长序列,用树状数组来求,O(logN)
但是因为j - i > d, 所以我们前 i - d 个元素不更新,j = i - d; 当j >= 0时,也就是
a[j] 这个元素可以“发挥作用了”,我们就更新树状数组, add( a[j], dp[j] )~~~~
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <stdio.h> #include <stdlib.h> #include <algorithm> #include <string.h> using namespace std; int num[100010]; int b[100010]; int tree[100010]; int dp[100010]; int N,d; int lowbit(int x) { return x&-x; } int query_max(int t) { int ans = 0; while( t ) { if(tree[t] > ans ) ans = tree[t]; t -= lowbit(t); } return ans; } void add(int t, int c) { while( t <= N ) { if( tree[t] < c ) tree[t] = c; t += lowbit(t); } } int main( ) { while( scanf("%d%d",&N,&d) != EOF) { memset(tree, 0, sizeof(tree)); for(int i = 0; i < N; ++i) { scanf("%d",&num[i]); b[i] = num[i]; } sort(b,b + N); int len = unique(b, b + N) - b; for(int i = 0; i < N; ++i) { num[i] = lower_bound(b, b + N, num[i] ) - b + 1; } int ans = 1, tmp, j; for(int i = 0; i < N; ++i) { tmp = query_max(num[i] - 1) + 1; if( tmp > ans ) ans = tmp; dp[i] = tmp; j = i - d; if( j >= 0 ) add(num[j], dp[j]); } printf("%d\n",ans); } return 0; }