BZOJ 4241 历史研究 (回滚莫队)
2017-07-25 14:41
1081 查看
4241: 历史研究
Time Limit: 80 Sec Memory Limit: 512 MBDescription
IOI国历史研究的第一人——JOI教授,最近获得了一份被认为是古代IOI国的住民写下的日记。JOI教授为了通过这份日记来研究古代IOI国的生活,开始着手调查日记中记载的事件。
日记中记录了连续N天发生的时间,大约每天发生一件。
事件有种类之分。第i天(1<=i<=N)发生的事件的种类用一个整数Xi表示,Xi越大,事件的规模就越大。
JOI教授决定用如下的方法分析这些日记:
1. 选择日记中连续的一些天作为分析的时间段
2. 事件种类t的重要度为t*(这段时间内重要度为t的事件数)
3. 计算出所有事件种类的重要度,输出其中的最大值
现在你被要求制作一个帮助教授分析的程序,每次给出分析的区间,你需要输出重要度的最大值。
4.
Input
第一行两个空格分隔的整数N和Q,表示日记一共记录了N天,询问有Q次。
接下来一行N个空格分隔的整数X1…XN,Xi表示第i天发生的事件的种类
Output
输出Q行,第i行(1<=i<=Q)一个整数,表示第i次询问的最大重要度
Sample Input
5 5
9 8 7 8 9
1 2
3 4
4 4
1 4
2 4
Sample Output
9
8
8
16
16
HINT
1<=N<=10^5
1<=Q<=10^5
1<=Xi<=10^9 (1<=i<=N)
题目大意:
有一个长度为n的序列。
有m个询问,每次询问l~r范围内每个数值乘以该数值出现次数的最大值。
思路:
听起来很玄奥的回滚莫队。
回滚莫队可以代替掉删除操作,让时间复杂度仍然保持在O(nsqrtn)。
分块和排序都按照基础莫队做法来,然后在统计答案的时候,如果一个询问的左端点和右端点在同一个块内,那就暴力统计。
然后对于左端点在同一块内的询问我们一起统计,首先让左端点在这一块的最右端,然后让右端点正常向右扩张。当右端点满足条件的时候,记录一下这个时候的状态,再把左端点调整到询问的左端点,这个时候统计一下答案,然后再回滚到没有调整左端点的时候的那个状态。然后再做下一个询问就可以了。
莫队。。。真是个卡暴力的好(e xin)方法
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #define N 120000 #define LL long long using namespace std; int n, m, block, pos; int a , aa , place , top; LL sum , num , pre, now, ans ; struct Query{ int l, r, id; }q ; bool cmp ( Query aa, Query bb ){//块内r,块外l return place[aa.l] < place[bb.l] || (place[aa.l] == place[bb.l] && aa.r < bb.r); } void adde(int c){ sum[c] += aa[c];//+-的是aa中的原值 now = max(now, sum[c]); } void del(int c){ sum[c] -= aa[c]; } int main(){ scanf("%d%d", &n, &m); block = (int) sqrt(n); for(int i=1; i<=n; i++){ scanf("%d", &a[i]); aa[i] = a[i]; } sort(aa+1, aa+1+n); top = unique(aa+1, aa+1+n) - aa;//去重 for(int i=1; i<=n; i++) a[i] = lower_bound(aa+1, aa+top, a[i]) - aa;//离散化 for(int i=1; i<=m; i++){ scanf("%d%d", &q[i].l, &q[i].r); q[i].id = i;//query排序 } for(int i=1; i<=n; i++) place[i] = (i-1) / block + 1; sort(q+1, q+1+m, cmp); int l, r; for(int i=1; i<=m; i++){ if(place[q[i].l] != place[q[i-1].l]){ memset(sum, 0, sizeof(sum)); pre = now = 0; l = pos = place[q[i].l] * block + 1;//l放到块的左端点上 r = l - 1;//保证初值为零 } if(place[q[i].l] == place[q[i].r]){//l,r在同一块中,不移动l,r暴力query LL cur = 0; for(int j=q[i].l; j<=q[i].r; j++){ num[a[j]] += aa[a[j]]; cur = max(cur, num[a[j]]); } for(int j=q[i].l; j<=q[i].r; j++)//还原 num[a[j]] -= aa[a[j]]; ans[q[i].id] = cur; continue; } while(r < q[i].r) adde( a[++r] );//添加信息 pre = now;//记录当前状态 while(l > q[i].l) adde( a[--l] ); ans[q[i].id] = now;//记录答案 while(l < pos) del( a[l++] );//还原(回滚) now = pre; } for(int i=1; i<=m; i++) printf("%lld\n", ans[i]); return 0; }
相关文章推荐
- [BZOJ]4241 历史研究 回滚莫队
- [BZOJ4241]-历史研究-回滚莫队
- BZOJ4241 历史研究 (分块 回滚莫队-教程向)
- [BZOJ4241]历史研究(回滚莫队)
- BZOJ.4241.历史研究(回滚莫队 分块)
- bzoj4241 历史研究 (回滚莫队)
- [bzoj4241]历史研究 回滚莫队
- 【BZOJ4241】【回滚莫队】历史研究 (非题解的学习分析)
- BZOJ4241 历史研究(莫队)
- BZOJ4241 历史研究 莫队算法 堆
- BZOJ 4241: 历史研究——莫队 二叉堆
- 【bzoj4241】历史研究 分块
- 【bzoj4241】 历史研究
- 【BZOJ4241】历史研究 分块
- [bzoj4241][历史研究] (分块)
- [分块] BZOJ 4241 历史研究
- [bzoj4241]历史研究
- bzoj 4241: 历史研究 分块
- BZOJ 4241 历史研究
- bzoj:4241: 历史研究