Codeforces 1690G 思维

题意:

n n n节火车车厢,从左到右依次是头至尾,每个车厢有一个最高速度 v i v_{i} vi,如果后面的车的速度不小于前车 v i + 1 ≥ v i v_{i+1}\geq v_{i} vi+1vi,那么后车的速度会受到限制,会变为前车速度 v i v_{i} vi,反之则不受影响。我们把连续的极长一段的共速车厢看作一辆完整火车。给出 m m m个操作,每个操作给出两个整数 x   d x x\ dx x dx,代表 x x x车厢的最高速度减少 d x dx dx,在每次操作后给出能组成的火车数。

方法:

利用 m a p map map v e c t o r vector vector,每次只保存火车头,在操作的时候,我们检查一下 x x x是否在 m a p map map里,如果在 m a p map map里有 x x x,那么这节火车头降速,然后检查后面的火车头速度是否不小于这个新的 v x v_{x} vx,如果后面的火车头的速度 ≥ v x \geq v_{x} vx,那么这个火车头会被 x x x同化,直接并入 x x x所在的火车,删去这个火车头即可;如果 m a p map map里没有 x x x,那么我们需要检查一下他是否脱离了前面火车头的控制,如果脱离了控制,就说明组成了一节新的火车,然后再检查后面的是否速度是否 ≥ \geq 这个新的火车头的速度,如果是,那么被这个新的同化,把后面的删去即可。每次操作后输出 m a p . s i z e ( ) map.size() map.size()即可

#include<bits/stdc++.h>
#define ll long long
#define fr first
#define se second
using namespace std;

int read()
{
	int ret=0,base=1;
	char ch=getchar();
	while(!isdigit(ch))
	{
		if(ch=='-') base=-1;
		ch=getchar();
	}
	while(isdigit(ch))
	{
		ret=(ret<<3)+(ret<<1)+ch-48;
		ch=getchar();
	}
	return ret*base;
}

int n,m,a[100005];
vector<int>ans;
map<int,int>map1;

void work()
{
	map1.clear();
	ans.clear();
	n=read();m=read();
	for(int i=1;i<=n;i++) a[i]=read();
	int l=1,r=1;
	while(l<=n)
	{
		while(r+1<=n&&a[r+1]>=a[l]) r++;
		map1[l]=a[l];
		l=++r;
	}
	while(m--)
	{
		int x=read(),dx=read();
		a[x]-=dx;
		if(map1.count(x))
		{
			map1[x]-=dx;
			auto it=map1.lower_bound(x); it++;
			while(it!=map1.end()&&it->se>=map1[x]){
				map1.erase(it--);it++;
			}
		}
		else
		{
			auto it=map1.lower_bound(x); it--;
			//it不可能是begin(),因为第一节车厢一定是一个火车头
			if(it->se>a[x]) 
			{
				map1[x]=a[x];
				it=map1.lower_bound(x); it++;
				while(it!=map1.end()&&it->se>=map1[x]){
					map1.erase(it--);it++;
				}
			}
		}
		ans.push_back(map1.size());
	}
	for(auto i:ans) printf("%d ",i);
	putchar('\n');
}

int main()
{
	int t=read();
	while(t--) work();
 	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值