GTW likes gt
Accepts: 54
Submissions: 782
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 131072/131072 K (Java/Others)
问题描述
从前,有n只萌萌的GT,他们分成了两组在一起玩游戏。他们会排列成一排,第i只GT会随机得到一个能力值bi。在第i秒的时候,第i只GT可以消灭掉所有排在他前面的和他不是同一组的且能力值小于他的GT。 为了使游戏更加有趣,GT的首领GTW会发功m次,第i次发功的时间为ci,则在第ci秒结束后,b1,b2,...,bci都会增加1。 现在,GTW想知道在第n秒之后,会有几只GT存活下来。
输入描述
第一行只有一个整数T(T≤5),表示测试数据组数。 第二行有两个整数n,m。表示GT的个数和GTW发功的次数。(1≤n≤50000,1≤m≤50000) 第三到n+2行,每行有两个整数ai,bi,表示第i只GT在哪个组和他的能力值 (0≤a[i]≤1,1≤b[i]≤106) 第n+3行到第n+m+2行,每行有一个整数ci,表示GTW第i次发功的时间。1≤c[i]≤n
输出描述
总共T行,第i行表示第i组数据中,GT存活的个数。
输入样例
1 4 3 0 3 1 2 0 3 1 1 1 3 4
输出样例
3
Hint
第1秒后 能力值为4 2 3 1 第2秒后 能力值为4 2 3 1 第3秒后 能力值为5 3 4 1,第2只GT被第3只GT消灭掉了 第4秒后 能力值为6 4 5 2 ci并不是有序的
题意:应该都可以看懂的,就不讲了。。。。
思路:用树状数组来实现任意区间更新,然后得到最终的序列(这样的好处是不用每过i秒再去判断a[i]前面有多少个会被其杀死),再利用逆序来保持最大值来寻找后面有多个能被其杀死,然后被杀死的就标记,最后统计没有被标记的个数就是答案了。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#include <cstring>
using namespace std;
#define maxn 51111
int n,m;
int bit[maxn],b[maxn];
int lowbit(int x){
return x&(-x);
}
void update(int x,int v){
while(x <= n){
bit[x] += v;
x += lowbit(x);
}
}
int sum(int x)
{
int s = 0;
while(x > 0)
{
s += bit[x];
x -= lowbit(x);
}
return s;
}
struct node
{
int x,vis;
}a[maxn];
int main()
{
#ifdef CDZSC_June
freopen("t.txt","r",stdin);
#endif
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
memset(bit,0,sizeof(bit));
for(int i = 1; i<=n; i++)
{
scanf("%d%d",&a[i].vis,&a[i].x);
update(i,a[i].x);
update(i+1,-a[i].x);
//把[i,i]的值设为a[i].x
}
for(int i = 1; i<=m; i++)
{
scanf("%d",&b[i]);
}
sort(b+1,b+m+1);
for(int i = 1; i<=m; i++)
{
update(1,1);//把[1,n]区间都加上1
update(b[i] + 1,-1);//把[b[i] + 1,n]区间都减去1
//这两句代码合起来的作用是把[1,b[i]]区间都加上1
}
for(int i = 1; i<=n; i++)
{
a[i].x = sum(i);//求出区间更新后的各个点的值
}
int max0,max1,p;
max0 = max1 = p= 0;
for(int i = n; i>= 1; i--)//逆序的好处是保证max的下标总在a[i]的后面,以便用来判断a[i]是否会被杀
{
if(a[i].vis ==1){
if(a[i].x > max1){
max1 = a[i].x;
}
if(max0 > a[i].x){
a[i].vis = 2;//意味着a[i]被杀死了,有可能a[i]被杀死多次;
//但是我每次都把a[i].vis赋值为2,到最后只要统计非2的元素个数就好
}
}
else if(a[i].vis == 0){
if(a[i].x > max0){
max0 = a[i].x;
}
if(max1 > a[i].x){
a[i].vis = 2;
}
}
}
for(int i = 1; i<=n; i++){
if(a[i].vis != 2)
p++;
}
printf("%d\n",p);
}
return 0;
}