飞跃(输入流同步,set容器)

题目

题目描述

有 n 朵花,此外有一个正整数 k 。第 i 朵花的高度为 ai。

一开始,Filip 在第1朵花上。

当她在第 i 朵花上时,她可以飞跃到第 j 朵花上,当且仅当:

  1. i < j

  2. | ai - aj | ≤ k

Filip 想要知道她能够飞跃到哪些花上。

输入格式

第一行,两个正整数 n, k

第二行,n 个正整数 a1, a2, ..., an

输出格式 n 个整数,第 i 个整数为 0 ,代表不能跳到第 i 朵花上;第 i 个整数为 1,代表可以跳到第 i 朵花上。

样例 #1
输入
5 2
5 4 8 7 2
输出
1 1 0 1 1

样例 #2
输入
5 3
10 15 14 8 9
输出
1 0 0 1 1

说明/提示

对于 100% 的数据,保证 1≤n≤2e5 ,1≤ai ,k≤1e9。

代码一+思路

使用 set 维护当前所有可达花的高度,并按如下步骤处理:

  1. 边输入边处理:每读入一个新花的高度 t,检查当前 set 中是否存在满足条件的高度(通过 upper_bound 和 prev 找到最近的左右边界)。

  2. 插入条件:如果存在相邻的高度与 t 的差值不超过 k,则插入 t 并标记为可达。

时间复杂度:每次插入和查询 set 的时间为 O(logn),总复杂度为 O(n logn)。

#include<bits/stdc++.h>
using namespace std;
 
int main(){
  int n,k;
  cin.tie(nullptr)->sync_with_stdio(false);\\可提高速度
  cin>>n>>k;
  set<int>s;\\STL容器,集合,会将其内元素从小到大排序
  int x; cin>>x; s.insert(x); cout<<"1 ";\\先插入第一个元素,并输入1
  while(--n){
    cin>>x;
    auto r=s.upper_bound(x);\\返回s集合中第一个大于x的数,由于返回的是一个指针,所以不能用int型
    auto l=prev(r);\\返回集合中小于x的最大数,即l和r是和x相邻的两个数,接下来只需判断他们的差是否小于k
    if((l!=s.end()&&abs((*l)-x)<=k)||(r!=s.end()&&abs((*r)-x)<=k)){
			s.insert(x);\\如果可以跳到这朵花上面,就将它插入集合中,并输出1
			cout<<"1 ";
		}
		else{cout<<"0 ";}\\否则输出0
	}
  return 0;
}

相关拓展1

cin.tie(nullptr)->sync_with_stdio(false)

它分为两个部分,sync_with_stdio(false) 的功能是:关闭C++标准流与C标准流I/O的同步。默认情况下,C++的 cin/cout 和C的 scanf/printf 是同步进行的(为了兼容性),但同步会导致性能损失。而调用 sync_with_stdio(false) 后,关闭同步,可以显著提高cin/cout的速度。

而 cin.tie(nullptr) 解除 cin 与 cout 的绑定。默认情况下,cin 在读取输入前会自动刷新 cout 的缓冲区(确保输出在输入前显示)。例如:

cout << "Enter a number: ";
cin >> x;

默认会先输出提示语,再等待输入。调用 cin.tie(nullptr) 后,cin 不再自动刷新 cout 的缓冲区,减少不必要的性能开销。

一、什么时候需要使用它?

  1. 处理大规模数据输入输出

场景:需要读取或写入 超过 1e5 数量级 的数据(例如算法竞赛、大数据处理)。

问题:默认的 cin/cout 速度较慢,可能导致超时。

优化效果:

输入速度提升约 5-10 倍。

输出速度提升约 2-5 倍。

  1. 算法竞赛或编程比赛

场景:在 Codeforces、LeetCode、ACM-ICPC 等平台提交代码。

原因:这些比赛对程序运行时间有严格限制,I/O 效率直接影响是否通过测试用例。

  1. 需要频繁的输入输出操作

场景:循环中多次读写数据,例如逐行处理文件或网络流。

问题:默认的 cin/cout 每次操作可能触发缓冲区刷新,累积耗时显著。

优化效果:减少缓冲区刷新次数,提升吞吐量。

二、什么时候不需要使用它?

  1. 小型程序或数据量极少

场景:输入输出数据量小于 1e4,或程序逻辑耗时远大于 I/O 时间。

原因:优化带来的性能提升微乎其微,代码可读性更重要。

场景:同时使用 cin/cout 和 scanf/printf。

问题:关闭同步后混用会导致输出顺序混乱或数据错误。

错误示例:

ios_base::sync_with_stdio(false);
cin.tie(nullptr);
int x;
cin >> x; // C++ 输入
printf("%d", x); // C 输出(可能导致问题)

  1. 需要即时交互的提示信息

场景:在输入前输出提示语(如 "Enter your name: ")。

问题:解除 cin 与 cout 的绑定后,提示语可能不会在输入前显示。

解决方法:手动刷新缓冲区:

cout << "Enter your name: " << flush; // 强制刷新
string name;
cin >> name;

三、使用时的注意事项

  1. 禁止混用 C/C++ I/O 函数

一旦调用 sync_with_stdio(false),必须只用 C++ 的 cin/cout,或者使用scanf/printf。而不能两者混用

  1. 避免使用 endl

endl 会强制刷新缓冲区,改用 '\n' 更高效。

相关拓展2

set
set叫集合,和数学上那个集合一样,所以里面的元素各不相同,并且会按从小到大帮你自动排好,基本用法如下

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main()
{
	set <int> s;//s后面不能加内容!!集合怎么能规定大小呢?
	s.insert(4);//插入 
	s.insert(3);
	s.insert(2);
	s.insert(1);
	for(auto p=s.begin();p!=s.end();p++)//也是可以用迭代器遍历输出
		{
			cout<<*p<<" ";
		}
		//从小到大自动排好序,所以应输出1 2 3 4
	cout<<endl;
	//find()是查找函数,其返回值是一个指针,所以只能用比较的方法来输出
	//要是找到了就说明在end()之前,反之则不在集合里,这个记住就行了
	cout<<"删除前 "<<(s.find(2)!=s.end())<<endl;
	s.erase(2);//删除操作,把s里面的2删除了
	cout<<"删除后 "<<(s.find(2)!=s.end())<<endl;
	for(auto p=s.begin();p!=s.end();p++)
	{
		cout<<*p<<" ";
	}
	return 0;
}

代码二+思路

维护前面的可以到达的最大和最小值,后一个只要满足可以跳到这两个值就行

#include<bits/stdc++.h>
using namespce std;
const int N=2e5+5;
 
int main(){
	int n,k,a[N],mx,mn;
	cin>>n>>k;
	for(int i=1; i<=n; i++){
		cin>>a[i];
		if(i==1){ mx=mn=a[i]; cout<<"1 ";}
		else{
			if(mn-k<=a[i]&&a[i]<=mx+k){
				cout<<"1 ";
				mx=max(mx,a[i]);
				mn=min(mn,a[i]);
			}
			else cout<<"0 ";
		}
	}
	return 0;
}

嗯。。这个思路啊,其实也没多难的样子,但是苯人当时并没有写出这道题来(真是太弱鸡了),题解都分析了好半天来着。

当然现在时隔小半年后再看,这道题是真的蛮简单的,,,

————————————————————

题目背景:译自https://hsin.hr/coci/
contest#1 T2

题目链接:https://hydro.ac/d/cduestc/p/2206

该文章内容已在CSDN上发表过,此处为二次编辑
https://blog.csdn.net/SDSSpJ306/article/details/148050801?spm=1011.2124.3001.6209

posted @ 2025-08-26 21:05  SDSSpJ306  阅读(26)  评论(0)    收藏  举报