51Nod - 1786 数据流中的算法 - 众数
Posted 晓风微微
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51Nod - 1786 数据流中的算法 - 众数相关的知识,希望对你有一定的参考价值。
基准时间限制:1.5 秒 空间限制:131072 KB 分值: 80 难度:5级算法题
数据流统计功能上线后,为51nod提升用户体验做出了很大的贡献。但是新问题随之而来,夹克老爷还想知道在一个窗口内,访问次数最多用户(即窗口内的众数)。如果有多个众数,取用户ID最小的一个。(窗口的意思是一个固定长度的区间!)
(因为数据流是实时的、在线的,所以不允许使用离线算法^_^)
Input
第一行为整数n, k。(1 <= n <= 5 * 10^6,1 <= k <= 1000) n代表有多少次操作,k代表窗口大小。 接下来的n行,每行代表一次操作。每行第一个整数为操作数。 操作数1:用户访问 输入格式: <1, id> 用户ID为[0, INT_MAX]闭区间内的整数。代表拥有此ID的用户对网站进行了一次访问,窗口进行相应移动。 操作数2:询问众数 输入格式:<2> 输出窗口内的众数,如果有多个,输出ID最小的那个。 p.s. 对于询问众数的操作,窗口保证不空 p.s.s. 对于询问众数的操作,窗口可能不满
Output
对于询问众数的操作,每行输出一个整数。
Input示例
10 5 1 2 1 1 1 2 1 1 1 2 1 1 2 1 3 1 3 2
Output示例
1 1
题目大意:
起初看到这道题,没读懂是什么意思,一直在纳闷窗口是啥。后来才明白,是实现查询,查询时的前k个访问次数中,访问最多的用户的编号。
分析:
首先,考虑到的是只考虑查询前的前k次访问,复杂度是k*查询次数,如果大部分都是查询明显过不去。
之后,用优先队列去实现,优先队列内容是一个结构体,储存了用户的ID,和访问次数。但是,优先队列不支持删除操作,
所以怎么去实现删除已经超过k个用户的数据呢?我的方法是使用map记录每个用户的访问次数,删除k个之前的用户时,只在map里将其更新。然后,查询时
去循环取优先队列顶部元素,检查这个元素储存的访问次数是否与map里记录的次数相同,如果不相同则该节点作废,出队,再取队列顶部元素,直到相同为止,
然后,交上去,就超时了,将map改成hash_map,优化了输入之后再交,700ms通过。
其实,优先队列写法挂了之后,并没又马上用hash_map,就将程序改为了用set去实现,set的最大值就是set中最后一个元素,插入删除复杂度,log(n),2000ms,超时。。。。。。然后又将map改成hash_map,优化了输入输出之后再交,
700ms通过。。。。。。
ps:hash_map用VC++去交就可以成功编译
//优先队列实现 #include<iostream> using namespace std; #include<queue> #include<cstdio> #include<hash_map> typedef long long LL; inline LL getint()//快速读入 { LL w = 0, q = 0; char c = getchar(); while ((c<‘0‘ || c>‘9‘) && c != ‘-‘) c = getchar(); if (c == ‘-‘) q = 1, c = getchar(); while (c >= ‘0‘&&c <= ‘9‘) w = w * 10 + c - ‘0‘, c = getchar(); return q ? -w : w; } queue<LL> team; struct data//优先队列里信息用的结构体 { LL sj; LL bh; bool operator<(const data &b)const { if (this->sj == b.sj) return this->bh>b.bh; return this->sj<b.sj; } }; priority_queue<data> preteam; hash_map<LL, LL> maps; int n, k; int main() { int rq = 0; cin >> n >> k; LL pre; int ml; LL dx; data mx; for (int i = 1; i <= n; i++) { //scanf("%d", &ml); ml = getint(); if (ml == 1) { //scanf("%lld", &dx); dx = getint(); data np; maps[dx]++; np.bh = dx; np.sj = maps[dx]; preteam.push(np); team.push(dx); if (team.size() == k + 1) { pre = team.front(); maps[pre]--; team.pop(); } } if (ml == 2) { mx = preteam.top(); /*循环取优先队列有效值*/ while (mx.sj != maps[mx.bh] && !preteam.empty()) { preteam.pop(); mx = preteam.top(); } printf("%d\n", mx.bh); } } return 0; }
//set实现 #include<iostream> using namespace std; #include<queue> #include<cstdio> #include<hash_map> #include<map> #include<set> typedef long long LL; queue<LL> team; inline LL getint() { LL w = 0, q = 0; char c = getchar(); while ((c<‘0‘ || c>‘9‘) && c != ‘-‘) c = getchar(); if (c == ‘-‘) q = 1, c = getchar(); while (c >= ‘0‘&&c <= ‘9‘) w = w * 10 + c - ‘0‘, c = getchar(); return q ? -w : w; } struct data { LL sj; LL bh; bool operator<(const data &b)const { if (this->sj == b.sj) return this->bh>b.bh; return this->sj<b.sj; } }; set<struct data> preset; hash_map<LL, LL> maps; int n, k; int main() { set<struct data>::iterator pt; int rq = 0; //cin>>n>>k; n = getint(); k = getint(); LL pre; int ml; LL dx; struct data mx; for (int i = 1; i <= n; i++) { //scanf("%d",&ml); ml = getint(); if (ml == 1) { dx = getint(); // scanf("%lld",&dx); struct data np; np.bh = dx; np.sj = maps[dx]; preset.erase(np); maps[dx]++; np.sj = maps[dx]; preset.insert(np); team.push(dx); if (team.size() == k + 1) { pre = team.front(); np.bh = pre; np.sj = maps[pre]; preset.erase(np); team.pop(); maps[pre]--; if (maps[pre] == 0) continue; np.sj = maps[pre]; preset.insert(np); } } if (ml == 2) { pt = preset.end(); --pt;//迭代器自减至set最后一个元素的位置 int bh = (*pt).bh; // cout<<bh<<endl; printf("%d\n", bh); } } return 0; }
以上是关于51Nod - 1786 数据流中的算法 - 众数的主要内容,如果未能解决你的问题,请参考以下文章