这题是来自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;
}