数据流中的算法 - 众数 51Nod - 1786
数据流统计功能上线后,为51nod提升用户体验做出了很大的贡献。但是新问题随之而来,夹克老爷还想知道在一个窗口内,访问次数最多用户(即窗口内的众数)。如果有多个众数,取用户ID最小的一个。(窗口的意思是一个固定长度的区间!)
(因为数据流是实时的、在线的,所以不允许使用离线算法^_^)
Input
第一行为整数n, k。(1 <= n <= 5 * 10^6,1 <= k <= 1000)
n代表有多少次操作,k代表窗口大小。
接下来的n行,每行代表一次操作。每行第一个整数为操作数。
操作数1:用户访问
输入格式: <1, id>
用户ID为0,INTMAX0,INTMAX闭区间内的整数。代表拥有此ID的用户对网站进行了一次访问,窗口进行相应移动。
操作数2:询问众数
输入格式:<2>
输出窗口内的众数,如果有多个,输出ID最小的那个。
p.s. 对于询问众数的操作,窗口保证不空
p.s.s. 对于询问众数的操作,窗口可能不满
Output
对于询问众数的操作,每行输出一个整数。
Sample Input
10 5 1 2 1 1 1 2 1 1 1 2 1 1 2 1 3 1 3 2
Sample Output
1 1
对STL的熟练运用,加上卡常,普通的scanf 和printf 都会很慢,手写一个输入输出流(俗称 输入挂,输出挂)
代码:
#include<bits/stdc++.h>
using namespace std;
struct node{
int id,cnt;
bool operator <(const node &a)const{
return cnt == a.cnt ? id < a.id:cnt > a.cnt;
}
};
int read()//输入挂
{
char ch = ' ';
int ans = 0;
while(ch <'0'|| ch >'9') ch = getchar();
while(ch >='0'&& ch <='9'){
ans = ans*10+ch - '0';
ch = getchar();
}
return ans;
}
void out(int a){//输出挂
if(a > 9){
out(a/10);
}
putchar(a%10 + '0');
}
int main()
{
int n,k;
int a,b;
queue<int >q;//存输入的id 可以判断存入的id是否大于k;
map<int ,int >f;//存id的数量;
set<node> s;//set 会自动排序 输出首位就是题目要求的数据数量最多id最小的(注意结构体重载)
n = read(),k =read();
for(int i = 0; i < n; i++){
a = read();
if(a == 1){
b = read();
f[b]++;//b的数量
s.insert(node{b,f[b]});//将输入的id存入set
if(q.size() == k){//如果输入的数据为k个的话那么如果还想输入就得将队列中的首位排出才能存入
s.erase(s.find((node){q.front(),f[q.front()]}));//找到队列的首位并且删除
f[q.front()]--;//队列的首位排出那么他的数量减一
if(f[q.front()]){//如果队列首位的数量大于1,那么就得把剩下的重新存入set因为他只删除了1个队列首位,与队列首位相等的id有很多
s.insert((node){q.front(),f[q.front()]});//重新存入set
}
if(f[q.front()] == 0){//如果队列首位代表的id数量减一之后为零直接清除掉 没有也行
f.erase(q.front());
}
q.pop();
}
q.push(b);
}
else{
out((*s.begin()).id);//输出set首位 s.begin()代表的是地址;
putchar('\n');
}
}}