HDU - 5596 - GTW likes gt
这题是来自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比较即可。
其实仔细想想,在第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\n", ans); } return 0; }