[BOI2007] Sound 静音问题(线段树)

[BOI2007] Sound 静音问题

题目描述

数字录音中,声音是用表示空气压力的数字序列描述的,序列中的每个值称为一个采样,每个采样之间间隔一定的时间。

很多声音处理任务都需要将录到的声音分成由静音隔开的几段非静音段。为了避免分成过多或者过少的非静音段,静音通常是这样定义的: m m m 个采样的序列,该序列中采样的最大值和最小值之差不超过一个特定的阈值 c c c

请你写一个程序,检测 n n n 个采样中的静音。

输入格式

第一行有三个整数 n , m , c n,m,c n,m,c 1 ≤ n ≤ 1 0 6 1\le n\le10^6 1n106 1 ≤ m ≤ 1 0 4 1\le m\le10^4 1m104 0 ≤ c ≤ 1 0 4 0\le c\le10^4 0c104),分别表示总的采样数、静音的长度和静音中允许的最大噪音程度。

2 2 2 n n n 个整数 a i a_i ai 0 ≤ a i ≤ 1 0 6 0\le a_i\le 10^6 0ai106),表示声音的每个采样值,每两个整数之间用空格隔开。

输出格式

列出了所有静音的起始位置 i i i i i i 满足 max ⁡ { a i , a i + 1 ⋯ a i + m − 1 } − min ⁡ { a i , a i + 1 ⋯ a i + m − 1 } ≤ c \max\{a_i,a_{i+1}\cdots a_{i+m-1}\}-\min\{a_i,a_{i+1}\cdots a_{i+m-1}\}\le c max{ai,ai+1ai+m1}min{ai,ai+1ai+m1}c),每行表示一段静音的起始位置,按照出现的先后顺序输出。如果没有静音则输出 NONE

样例 #1

样例输入 #1

7 2 0
0 1 1 2 3 2 2

样例输出 #1

2
6

解析

线段树跑一遍,注意题意为全部的区间,可以重叠,i 不要跳转
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define L u<<1
#define R u<<1|1
#define inf 0x3f3f3f3f
const int N=1e6+5;
int n,m,c,a[N];
struct node{
	int l,r;
	int smax,smin;
}tr[N*4];
void build(int u,int l,int r){
	tr[u].l=l,tr[u].r=r;
	if(l==r){
		tr[u].smax=tr[u].smin=a[l];
		return;
	}
	int mid=l+r>>1;
	build(L,l,mid),build(R,mid+1,r);
	tr[u].smax=max(tr[L].smax,tr[R].smax);
	tr[u].smin=min(tr[L].smin,tr[R].smin);
}
pair<int,int> query(int u,int l,int r){	
	if(tr[u].l>=l&&tr[u].r<=r) 
		return {tr[u].smax,tr[u].smin};
	int mid=tr[u].l+tr[u].r>>1;
	int tmax=0,tmin=inf;
	if(l<=mid){
		pair<int,int>p=query(L,l,r);
		tmax=max(tmax,p.first);
		tmin=min(tmin,p.second);
	}
	if(r>mid){
		pair<int,int>p=query(R,l,r);
		tmax=max(tmax,p.first);
		tmin=min(tmin,p.second);
	}
	return {tmax,tmin};
}
void solve(){
	scanf("%lld%lld%lld",&n,&m,&c);
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	build(1,1,n);
	int f=1;
	for(int i=1;i<=n-m+1;i++){
		pair<int,int>ans=query(1,i,i+m-1);
		if(ans.first-ans.second<=c){
			printf("%lld\n",i);
			f=0;
//			i+=m-1; 	//此处不需要添加 
		}
	}
	if(f) puts("NONE");
}
signed main(){
	int t=1;
//	scanf("%d",&t);
	while(t--) solve();
	return 0;
}
  • 19
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值