[BZOJ 4241] 歷史研究

BZOJ傳送門

題目描述

IOI國曆史研究的第一人——JOI教授,最近獲得了一份被認爲是古代IOI國的住民寫下的日記。JOI教授爲了通過這份日記來研究古代IOI國的生活,開始着手調查日記中記載的事件。

日記中記錄了連續NN天發生的時間,大約每天發生一件。

事件有種類之分。第ii(1iN)(1\le i\le N)發生的事件的種類用一個整數XiX_i表示,XiX_i越大,事件的規模就越大。

JOI教授決定用如下的方法分析這些日記:

  1. 選擇日記中連續的一些天作爲分析的時間段

  2. 事件種類tt的重要度爲tt*(這段時間內重要度爲tt的事件數)

  3. 計算出所有事件種類的重要度,輸出其中的最大值

現在你被要求製作一個幫助教授分析的程序,每次給出分析的區間,你需要輸出重要度的最大值。

輸入輸出格式

輸入格式

第一行兩個空格分隔的整數NNQQ,表示日記一共記錄了NN天,詢問有QQ次。

接下來一行NN個空格分隔的整數X1...XNX_1...X_NXiX_i表示第ii天發生的事件的種類

接下來QQ行,第ii(1iQ)(1\le i\le Q)有兩個空格分隔整數AiA_iBiB_i,表示第ii次詢問的區間爲[Ai,Bi][A_i,B_i]

輸出格式

輸出QQ行,第ii(1iQ)(1\le i\le Q)一個整數,表示第ii次詢問的最大重要度

輸入輸出樣例

輸入樣例#1:

5 5
9 8 7 8 9
1 2
3 4
4 4
1 4
2 4

輸出樣例#1:

9
8
8
16
16

解題分析

如果用普通莫隊在刪除時無法維護次大值, 需要一個setset, 就GG了。

所以去學了新姿勢: 回滾莫隊。

還是分塊, 把左端點在一塊的詢問按右端點從小到大排序。

如果左右端點都在一塊先處理掉。

然後我們只維護左端點在當前左端點所在塊最右端, 且右端點單調遞增的答案, 每次動態插入左邊塊內的元素統計答案後再撤銷。

總複雜度還是QNQ\sqrt N的。

代碼如下:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <vector>
#include <tr1/unordered_map>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 100500
#define ll long long
template <class T>
IN void in(T &x)
{
	x = 0; R char c = gc;
	for (; !isdigit(c); c = gc);
	for (;  isdigit(c); c = gc)
	x = (x << 1) + (x << 3) + c - 48;
}
template <class T> IN T max(T a, T b) {return a > b ? a : b;}
std::tr1::unordered_map <int, int> mp;
int n, m, sqr, qcnt, arr, bcnt;
ll ans[MX];
int blk[MX], val[MX], cnt[MX], id[MX];
struct Query {int l, r, id;};
IN bool operator < (const Query &x, const Query &y) {return x.r < y.r;}
std::vector <Query> que[500];
int main(void)
{
	int foo, bar, cur, siz;
	R ll rem, mx;
	in(n), in(m); sqr = std::sqrt(n); bcnt = n / sqr;
	for (R int i = 1; i <= n; ++i)
	{
		in(foo), blk[i] = i / sqr;
		if (!mp[foo]) mp[foo] = ++arr, val[arr] = foo;
		id[i] = mp[foo];
	}
	for (R int i = 1; i <= m; ++i)
	{
		in(foo), in(bar);
		if (blk[foo] == blk[bar])
		{
			mx = 0;
			for (R int j = foo; j <= bar; ++j)
			{
				++cnt[id[j]];
				mx = max(1ll * cnt[id[j]] * val[id[j]], mx);
			}
			ans[i] = mx; mx = 0;
			for (R int j = foo; j <= bar; ++j) --cnt[id[j]];
		}
		else que[foo / sqr].push_back({foo, bar, i});
	}
	std::sort(que + 1, que + 1 + qcnt);
	for (R int i = 0; i <= bcnt; ++i)
	{
		std::sort(que[i].begin(), que[i].end());
		std::memset(cnt, mx = 0, sizeof(cnt));
		cur = (i + 1) * sqr - 1, siz = que[i].size();
		for (R int j = 0; j < siz; ++j)
		{
			W (cur < que[i][j].r)
			{
				++cur;
				++cnt[id[cur]];
				mx = max(mx, 1ll * cnt[id[cur]] * val[id[cur]]);
			}
			rem = mx;
			for (R int k = (i + 1) * sqr - 1; k >= que[i][j].l; --k)
			{
				++cnt[id[k]];
				mx = max(mx, 1ll * cnt[id[k]] * val[id[k]]);
			}
			ans[que[i][j].id] = mx;
			for (R int k = (i + 1) * sqr - 1; k >= que[i][j].l; --k) --cnt[id[k]];
			mx = rem;
		}
	}
	for (R int i = 1; i <= m; ++i) printf("%lld\n", ans[i]);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章