BestCoder Round #66 (div.2)-GTW likes gt(模拟好题)

GTW likes gt

 
 Accepts: 54
 
 Submissions: 782
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 131072/131072 K (Java/Others)
问题描述
从前,有nn只萌萌的GT,他们分成了两组在一起玩游戏。他们会排列成一排,第ii只GT会随机得到一个能力值b_ibi。在第ii秒的时候,第ii只GT可以消灭掉所有排在他前面的和他不是同一组的且能力值小于他的GT。
为了使游戏更加有趣,GT的首领GTW会发功mm次,第ii次发功的时间为c_ici,则在第c_ici秒结束后,b_1,b_2,...,b_{c_i}b1,b2,...,bci都会增加1。
现在,GTW想知道在第nn秒之后,会有几只GT存活下来。
输入描述
第一行只有一个整数T(T\leq 5)T(T5),表示测试数据组数。
第二行有两个整数n,mn,m。表示GT的个数和GTW发功的次数。(1\leq n \leq 50000,1\leq m\leq 500001n50000,1m50000)
第三到n+2n+2行,每行有两个整数a_i,b_iai,bi,表示第ii只GT在哪个组和他的能力值 (0\leq a[i]\leq 1,1\leq b[i]\leq 10^6)(0a[i]1,1b[i]106)n+3n+3行到第n+m+2n+m+2行,每行有一个整数c_ici,表示GTW第ii次发功的时间。1\leq c[i]\leq n1c[i]n
输出描述
总共TT行,第ii行表示第ii组数据中,GT存活的个数。
输入样例
1
4 3
0 3
1 2
0 3
1 1
1
3
4
输出样例
3
Hint
11秒后 能力值为4\ 2\ 3\ 14 2 3 122秒后 能力值为4\ 2\ 3\ 14 2 3 133秒后 能力值为5\ 3\ 4\ 15 3 4 1,第22只GT被第33只GT消灭掉了
第44秒后 能力值为6\ 4\ 5\ 26 4 5 2
c_ici并不是有序的
 
 
思路:
   这题我一开始更不毫无头绪,最后也没做出来。最困惑的是如何在每一秒中更新【1,c【i】】的值。结果看了题解后发现自己的思路是认为要从前向后去做,而这里就隐藏了一个解题关键,每次更新在前面的数都是会不断被更新的,而这个更新是不会影响后面的一致性。
例如:
 
 
33秒后 能力值为5\ 3\ 4\ 15 3 4 144秒后 能力值为6\ 4\ 5\ 26 4 5 2
这里的5-4,与下面的6-5的关系是不改变的。所以我们就知道从后到前是可行的。
有了上面的基础后就是贪心了,所以我只要用两个变量去代表两个组的最大值,那么我只要比较后面的数是否比这两个
变量小,如果小则说明是可以将他杀掉。
 
 
线段树AC代码:
 
 
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdio>
using namespace std;
#define T 100005
#define inf 0x3f3f3f3f3f3f3f3fL
#define lson (rt<<1)
#define rson (rt<<1|1)
struct node
{
	int L,R,mid;
	int sum,lazy;
}tree[T<<2];

struct no
{
	int num,v;
}a[T];

void Pushdown(int rt)
{
	int u = tree[rt].lazy/*,v = (tree[rt].R-tree[rt].L+1)*/;
	if(u){
	/*	tree[rson].sum += v*u;
		tree[lson].sum += v*u;*/
		tree[rson].lazy += u;
		tree[lson].lazy += u;
		tree[rt].lazy = 0;
	}
}

void build(int rt,int L,int R)
{
	tree[rt].L = L,tree[rt].R = R;
	tree[rt].mid = (L+R)>>1;
	tree[rt].lazy = 0;
	if(L==R){
		tree[rt].sum=a[L].v;
		return;
	}
	build(lson,L,tree[rt].mid);
	build(rson,tree[rt].mid+1,R);
}

void update(int rt,int L,int R)
{
	if(L<=tree[rt].L&&tree[rt].R<=R){
		tree[rt].lazy ++;
		return;
	}
	Pushdown(rt);
	if(R<=tree[rt].mid){
		update(lson,L,R);
	}
	else if(L>tree[rt].mid)
	{
		update(rson,L,R);
	}
	else
	{
		update(lson,L,tree[rt].mid);
		update(rson,tree[rt].mid+1,R);
	}
}

void query(int rt)
{
	if(tree[rt].L==tree[rt].R){
		a[tree[rt].L].v = tree[rt].lazy+tree[rt].sum;
		return;
	}
	Pushdown(rt);
	query(lson);
	query(rson);
}

int sum[T];

int main()
{
#ifdef zsc
	freopen("input.txt","r",stdin);
#endif
	int N,n,m,i,j,k;
	scanf("%d",&N);
	while(N--)
	{
		scanf("%d%d",&n,&m);
		for(i=1;i<=n;++i){
			scanf("%d%d",&a[i].num,&a[i].v);
		}
		build(1,1,n);
		for(i=0;i<m;++i){
			scanf("%d",&k);
			update(1,1,k);
		}
		query(1);
		/*for(i=1;i<=n;++i){
			printf("%d ",a[i].v);
		}
		printf("\n");*/
		int ma[2]={0},c=0;
		for(i=n;i>0;--i){
			if(a[i].v>ma[a[i].num]){
				ma[a[i].num] = max(a[i].v,ma[a[i].num]);
			}
			if(a[i].v<ma[!a[i].num]){
				c++;
			}
		}
		printf("%d\n",n-c);
	}
	return 0;
}


 
 
AC代码:
#include<iostream>
#define cal(x,y) memset(x,y,sizeof(x))
#define T 50010
using namespace std;
int N,n,m,i,j,k;
int flag[T],num[T],w[T],v[T];
int main() {
#ifdef zsc
	freopen("input.txt","r",stdin);
#endif
	scanf("%d",&N);
	while(N--)
	{
		scanf("%d%d",&n,&m);
		cal(v,0);cal(flag,0);
		for(i=1;i<=n;++i){
			scanf("%d%d",num+i,w+i);
		}
		for(i=1;i<=m;++i){
			scanf("%d",&j);
			flag[j]++;//标记要加一的数
		}
		int vis[2] ={0};//这个数组非常巧妙,实现了两个组中的双互切换
		int cnt = 0;
		for(i=n;i>0;--i){
			 cnt += flag[i];//后面的数要加的值
			 int tmp = w[i] + cnt;//n秒后的真是数值
			 if(tmp<vis[!num[i]]){//少于前面的数,减去
				 v[i]=1;
			 }
			 if(vis[num[i]]<tmp){//更新两个组的最大值
				 vis[num[i]]=tmp;
			 }
		}
		int c =n;
		for(i=1;i<=n;++i){
			if(v[i])c--;
		}
		printf("%d\n",c);
	}
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值