P1440 求m区间内的最小值

提供一个比较清奇的思路 第一次想出和题解不一样的思路,好激动

看到题解都是大佬再秀,自认为我的思路好理解一些(桶加上优先队列)

思路

首先我们要明确的是实现什么

用优先队列做实现的就是两个:出队和进队

进队好办,一个push操作就解决了

但是出队呢,用优先队列似乎有一丢丢难办

那我们要解决的就是出队了

出队

假设队列中元素为{1 3 5 6 7 9}

那么让1出队简单,一个pop的事

那么要让后面的出队呢?

很显然,只有对首元素会影响到答案,首不就是答案吗?

就算队列有成千上万的元素需要出队对当前队列也没有影响

那么我们可以等到当要出队的对象到达队首时再出队

那么我们就需要用一个东西标记他是不是该出队(也就是桶)

桶存放的大小就为它在队列中的数量,显然当数量为0时就该出队了

所以我们在k该进队时就t[k]++;

对应,当k该出队列时就t[k]--;

只要!t[q.top]就q.pop( );

思路就这样

代码

#include<bits/stdc++.h>
#define end putchar('\n')
using namespace std;
inline int read( ){
	int sum=0;
	bool ft=0;
	char ch=getchar( );
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar( );
	if(ch=='-')ft=1,ch=getchar( );
	while(ch>='0'&&ch<='9'){
		sum=sum*10+ch-'0';
		ch=getchar( );
	}
	return ft?-sum:sum;
}
inline void print(int sum){
	char a[30];
	short w=0;
	bool ft=0;
	if(sum<0)sum=-sum,ft=1;
	while(sum)a[++w]=sum%10+'0',sum/=10;
	if(ft)putchar('-');
	while(w)putchar(a[w--]);
}                            //我也不知道为什么要打快读快写
int t[30000100],n,m,tot=1,a[3000000];
priority_queue<int,vector<int>,greater<int> >q;
int main( ){
	n=read( ),m=read( );
	putchar('0');                //第一个数肯定是0
	end;
	int k,x=1,r=m;
	n=n-1-m;
	while(r--){                  //入队+输出
		a[++tot]=read( );
		k=a[tot];
		if(!t[k])q.push(k);     //小小剪枝,只用一个值代替所有相同值
		++t[k];             //队列中t的个数+1
		print(q.top( ));
		end;
	}
	while(n--){
		a[++tot]=read( );
		k=a[tot];
		if(!t[k])q.push(k);       //小小剪枝,同上
		++t[k];
		while(x<=tot-m){         //不在区间范围内的出队
			--t[a[x]];
			++x;
		}
		while(!t[q.top( )])
       q.pop( );     //只要被标记为队列不该有这个数就出队
		print(q.top( ));
		end;
	}
}

双倍经验

或许我讲的不好,但是...

Geass,给我点赞吧

posted @ 2020-02-03 16:20  Mikasa_Ackerman  阅读(59)  评论(0编辑  收藏  举报