模板汇总 —— 杨式图表

HDU - 6642

使用范围:

求k个不相交的子序列最大值之和。

用法:

开k个map, 每次对于新的一个v,我们插入 v 个 v 到第一层中。

插入方式:

1.如果没有数比这个v大, 我们就直接将v放入到该层。

2.否则大于v的最小的数x,用v来替换x,将x插入下一层。

因为不能一个一个插入,所以用map来一起插入。

最后答案就是所有表内的元素个数之和。

复杂度为(2^knlog(n))

 

原理(口胡版):

首先考虑,用数组直接求LIS问题,我们数组的最后其实并不一定是一个LIS,我们只是求出了一个最易于后续扩张的数组。

对于杨表来讲,其实也一样,我们其实并没有保证了他的一个表内的数组完全是合法的,我们也一样找到了一个最易于后续扩张的一个数组。

对于贡献来讲, 我们一开始其实在插入数的时候,就已经把贡献给算完了,只有这个数的所有数都被其他数删除的时候,他对答案才不会有影响。

考虑 1 7 5 5 这个序列,且只有一层的杨表。

我们插入1 7之后,  表内为  1 7777777.

然后我们插入一个5, 表内为 1 5555577.

我们可以发现在这个过程中,还是由7对答案产生的一个影响。

我们再插入一个5,表内为 1 5555555 555.

我们就发现答案会加上3。

 

总结的话,也就是说,我们一旦成功(插入方式1)的插入某个数,我门就会对答案产生影响, 但是如果我们使用替换(插入方式2)来插入某个数的话,其实他的影响还是被原来的那个数给控制的。

 

#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const int _inf = 0xc0c0c0c0;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL _INF = 0xc0c0c0c0c0c0c0c0;
const LL mod =  (int)1e9+7;
const int N = 2e5 +100;
map<int, LL> mp[5];
const int k = 5;
LL ans = 0;
void Insert(int v, int num, int id){
    if(id == k){
        return ;
    }
    map<int, LL>::iterator it;
    while(num){
        it = mp[id].upper_bound(v);
        if(it == mp[id].end()) {
            ans += num;
            mp[id][v] += num;
            num = 0;
        }
        else {
            int mn = min((LL)num, it->se);
            it->se -= mn;
            if(it->se == 0) mp[id].erase(it);
            Insert(it->fi, mn, id+1);
            mp[id][v] += mn;
            num -= mn;
        }
    }
}
int main(){
    int T;
    scanf("%d", &T);
    while(T--){
        int n;
        for(int i = 0; i < 5; ++i) mp[i].clear();
        scanf("%d", &n);
        ans = 0;
        for(int i = 1, v; i <= n; ++i){
            scanf("%d", &v);
            Insert(v, v, 0);
            printf("%lld%c", ans, " \n"[i==n]);
        }
    }
    return 0;
}
View Code

 

posted @ 2019-08-13 16:17  Schenker  阅读(346)  评论(0编辑  收藏  举报