HDU

这题是来自BestCoder Round #66的一道题目,不是很难,官方题解上说的也比较清楚了。O(nlog(n))的算法真心没考虑,一开始想的就是O(n)的算法,看了题解之后居然还是没想到O(nlogn)的算法怎么写。
其实仔细想想,在第Ci秒结束时,B1, B2, B3, ... Bci都增加1,这一看就觉得是区间更新(唔,有种线段树的感觉),但是考虑区间更新来写,实在是有些麻烦,不如反向来想,如果我们在Ci + 1的位置开始一直到n都减1,结果也是一样的,那么就可以先在Ci+1的位置标记一下,然后更新整个数组,就得到所有人应当减少的val,同时计算最终的val,过程应当是O(n)的。然后再反推存活人数,我们知道,一个gt存活的条件在于,排在它后面的且不在同一组的gt的val值都比它自身的val小,不然的话,至少存在一个不同组的gt能够杀死这个gt,那么只需要记录一下,从i到n内两组gt的val最大值,再与第i个gt的val比较即可。

下面是代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 50000 + 10;
struct{
    int val;
    bool zu;
}gt[maxn];
int c[maxn];
inline int Max(int a, int b){
    return (a > b ? a : b);
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--){
        int n, m;
        memset(c, 0, sizeof(c));
        memset(gt, 0, sizeof(gt));
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; ++i){
            scanf("%d%d", >[i].zu, >[i].val);
        }
        for(int i = 1; i <= m; ++i){
            int tt;
            scanf("%d", &tt);
            --c[tt+1];
        }
        for(int i = 1; i <= n; ++i){
            c[i] += c[i-1];
            gt[i].val += c[i];
        }

        int ans = 0;
        int max0 = 0x80000000, max1 = 0x80000000;
        for(int i = n; i > 0; --i){
            if(gt[i].zu){
                if(gt[i].val > max0) ++ans;
                max1 = Max(max1, gt[i].val);
            }else{
                if(gt[i].val > max1) ++ans;
                max0 = Max(max0, gt[i].val);
            }
        }
        printf("%d
", ans);
    }
    return 0;
}


原文地址:https://www.cnblogs.com/wiklvrain/p/8179485.html