树状数组

树状数组专题

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] )~~~~

代码:

View Code
#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;
}

 

 

posted on 2013-03-26 15:15  luckyboy1991  阅读(185)  评论(0编辑  收藏  举报