hdu5125 magic balls BIT求LIS

分析:我们可以用dp[i][j]表示i为结尾的使用了j点体力的最大值,因为分a和b,所以再加1维,dp[i][j][0]表示a,dp[i][j][1]表示b,然后状态转移方程是这样的

dp[i]j[j][0] = max{dp[k][j][0], k < i,a[k] < a[i]}, max(dp[k][j][1], k < i, b[k] < a[i]);

dp[i][j][1] = max{dp[k][j-1][0], k < i,a[k] < b[i]}, max(dp[k][j-1][1], k < i, b[k] < b[i]);

但是这样时间复杂度是指数级的

然后我们可以用把a,b数组离散化后用BIT记录使用了j点体力的最大值,先查询,然后更新BIT,这样就变成了n*m*logn,然后注意的是循环的顺序,外循环是从0到n,

内循环从m到0而不是从0到m。举例:a[0] = 1, b[0] = 2, 那么在内圈从0循环到1的时候b[0] 会利用a[0]的值扩大LIS,而这是错误的,a[0]和b[0]不可同时存在的。

#include
#include
#include
using namespace std;
const int N = 1009;
int nn;
int a[N],b[N];
int h[N * 2];
struct BIT{
    int c[2*N];
    int lowbit(int x){return x & -x;}
    void update(int x, int k){
        while(x <= nn){
            c[x] = max(c[x], k);
            x += lowbit(x);
        }
    }
    int query(int x){
        int ret = 0;
        while(x > 0){
            ret = max(ret ,c[x]);
            x -= lowbit(x);
        }
        return ret;
    }
}t[N];
int main(){
    int T;scanf("%d", &T);
    while(T--){
        int m, n;
        scanf("%d%d", &n, &m);
        for(int i = 0; i < n; i++){
            scanf("%d%d", &a[i], &b[i]);
            h[i] = a[i]; h[i+n] = b[i];
        }
        sort(h, h + 2 * n);
        nn = unique(h, h + 2 * n) - h;
        for(int i = 0; i < n; i++){
            a[i] = lower_bound(h, h + nn, a[i]) - h + 1;
            b[i] = lower_bound(h, h + nn, b[i]) - h + 1;
        }
        int ma = 1;
        memset(t, 0, sizeof(t));
        for(int i = 0; i < n; i++){
            for(int j = m; j >= 0; j--){
                int x1 = t[j].query(a[i] - 1) + 1;
                if(x1 > ma) ma = x1;
                t[j].update(a[i], x1);
                if(j > 0){
                    int x2 = t[j-1].query(b[i] - 1) + 1;
                    if(x2 > ma) ma = x2;
                    t[j].update(b[i], x2);
                }
            }
        }
        printf("%d\n", ma);
    }
    return 0;
}


你可能感兴趣的:(线段树_树状数组)