P3709 大爷的字符串题(莫队+离散化)

P3709 大爷的字符串题

题目背景

在那遥远的西南有一所学校,

/被和谐部分/

然后去参加该省省选虐场,

然后某蒟蒻不会做,所以也出了一个字符串题:

题目描述

给你一个字符串 (a),每次询问一段区间的贡献。

贡献定义:

每次从这个区间中拿出一个字符 (x) ,然后把 (x) 从这个区间中删除,直到区间为空。你要维护一个集合 (S)

  • 如果 (S) 为空,你 (rp)(1)
  • 如果 (S) 中有一个元素不小于 (x),则你 (rp)(1),清空 (S)
  • 之后将 (x) 插入 (S)

由于你是大爷,平时做过的题考试都会考到,所以每次询问你搞完这段区间的字符之后最多还有多少 (rp)(rp) 初始为 (0)

询问之间不互相影响~

输入格式

第一行两个整数 (n,m),表示字符串长度与询问次数。

之后一行 (n) 个数,第 (i) 个整数表示给出的字符串的第 (i) 个字符 (x_i)

接下来 (m) 行,每行两个整数 (l, r),表示一次询问的区间。

输出格式

对于每次询问,输出一行一个整数表示答案。

输入输出样例

输入 #1

3 3
3 3 3
3 3
3 3
3 3

输出 #1

-1
-1
-1

说明/提示

数据规模与约定

  • 对于 (10\%) 的数据,是样例。
  • 对于另外 (10\%) 的数据,保证 (n,m le 100;)
  • 对于另外 (10\%) 的数据,保证 (n,m le 10^3;)
  • 对于另外 (10\%) 的数据,保证 (n,m le 10^4;)
  • 对于另外 (10\%) 的数据,保证 (n,m le 10^5;)
  • 对于 (100\%) 的数据,(1 leq n,m le 2 imes10^5,1 leq a_i leq 10^9,1 leq l, r leq n。)

保证数据像某省省选 day1T2 一样 sb,大家尽情用暴力水过题吧!

没事,你只要在一个好学校,就算这题只能拿到 10 分,也可以进队了。

Solution

唔,其实这是道语文题,题目要求
给定一个区间,求区间内众数的出现次数

为啥是这样,我们看这样一个样例

111122233345
12345/123/123/1

可以发现我们把序列排成一段一段的递增序列是最优的,每进入新的一段,(rp)就会-1
段落数也就是求出现次数最多的数的出现次数,因为后面段落出现的数一定也在前面的段落中出现过

用莫队求解
我们用(cnt[x])表示(x)的出现次数,很明显在(add())(ans=max(ans,cnt[x]))

但是删除的时候,可能会遇到这样一个问题,当前的(cnt[x])恰好就等于(ans),那我们能直接使(ans--)吗?不能!因为可能还有其他的(cnt[y])也等于(ans),删掉一个(x)不足以改变我们的答案

所以现在还要开一个数组(p[cnt]),表示出现次数为(cnt)的数字有多少个
(remove())函数中,如果当前的(cnt[x]==ans)并且(p[cnt[x]]==1),我们才能使ans--

嗷,有一个细节,这道题的值域范围是(10^9),需要离散

Code

#include<bits/stdc++.h>
#define il inline
#define rg register
#define lol long long
#define in(i) (i=read())
using namespace std;

const  int N=2e5+5;

int read() {
    int ans=0,f=1; char i=getchar();
    while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
    while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+(i^48),i=getchar();
    return ans*f;
}

int n,m,k,block,ans;
int a[N],sum[N],cnt[N],p[N],b[N];

struct query{
	int l,r,id,pos;
	bool operator < (const query &a) const {
		return pos==a.pos?r<a.r:pos<a.pos;
	}
}t[N];

void add(int x) {
	p[cnt[a[x]]]--;
	cnt[a[x]]++;
	p[cnt[a[x]]]++;
	ans=max(ans,cnt[a[x]]);
}

void remove(int x) {
	if(p[cnt[a[x]]]==1 && ans==cnt[a[x]]) ans--;
	p[cnt[a[x]]]--;
	cnt[a[x]]--;
	p[cnt[a[x]]]++;
}

int main() {
	in(n), in(m); block=3*sqrt(n);
	for (rg int i=1;i<=n;i++) in(a[i]),b[i]=a[i];
	sort(b+1,b+1+n); int len=unique(b+1,b+1+n)-b-1;
	for (int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+len,a[i])-b;
	for (rg int i=1,l,r;i<=m;i++)  {
		in(l), in(r);
		t[i].l=l, t[i].r=r;
		t[i].id=i;
		t[i].pos=(l-1)/block+1;
	}
	sort(t+1,t+1+m);
	for (rg int i=1,curl=1,curr=0;i<=m;i++) {
		rg int l=t[i].l,r=t[i].r;
		while(curl<l) remove(curl++);
		while(curl>l) add(--curl);
		while(curr<r) add(++curr);
		while(curr>r) remove(curr--);
		sum[t[i].id]=-ans;
	}
	for (rg int i=1;i<=m;i++) cout<<sum[i]<<endl;
}
博主蒟蒻,随意转载.但必须附上原文链接
http://www.cnblogs.com/real-l/
原文地址:https://www.cnblogs.com/real-l/p/15171668.html