题意:
就是让你找那个众数在询问的区间内出现了多少次,就比如样例:
3 3 3 3 3 3 3 3 3 3 3
他询问你[3,3]这个区间的值,我们可以看出来3就是那个众数,这个数在[3,3]区间内出现了1次,所以np(np原本为0)就减去1,所以输出-1
至于为什么是求众数?可以看:
就比如说这个数列1,1,1,2,2,4,5,6,6,7
我们把它排成一段一段的递增序列可以使rp掉的最少
就变成了1,2,4,5,6,7,1,2,6,1共掉3点rp
然后发现递增序列的个数就等于区间众数的出现次数
求众数,我们就需要维护最大值(之前做了一道回滚莫队,我一看维护最大值就感觉是回滚莫队,难搞 -_-)。普通莫队就可以解决它
我们用一个cnt数组来记录一个数出现的次数,再使用sum[i]数组来记录有多少数出现了i次
这个样子的话我们使用maxx来维护最大值,如果添加元素,那就每次比较取最大
maxx=max(maxx,cnt[typ[l]]);
如果删除元素,如果满足下面的判断,就让maxx减去1
if(cnt[typ[r]]==maxx && sum[cnt[typ[r]]]==1) { maxx--; }
代码:
#include <map> #include <set> #include <list> #include <queue> #include <deque> #include <cmath> #include <stack> #include <vector> #include <bitset> #include <cstdio> #include <string> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 2e5+10; const int INF = 0x3f3f3f3f; const double PI = 3.1415926; const long long N = 1000006; const double eps = 1e-10; typedef long long ll; #define mem(A, B) memset(A, B, sizeof(A)) #define lson rt<<1 , L, mid #define rson rt<<1|1 , mid + 1, R #define ls rt<<1 #define rs rt<<1|1 #define SIS std::ios::sync_with_stdiget_mod_new(z-x)o(false), cin.tie(0), cout.tie(0) #define pll pair<long long, long long> #define lowbit(abcd) (abcd & (-abcd)) #define max(a, b) ((a > b) ? (a) : (b)) #define min(a, b) ((a < b) ? (a) : (b)) inline int read() { //读取整数 int res = 0; char c = getchar(); while(!isdigit(c)) c = getchar(); while(isdigit(c)) res = (res << 1) + (res << 3) + (c ^ 48), c = getchar(); return res; } struct Node{ int l,r,id; }node[maxn]; int arr[maxn],ans[maxn],belong[maxn],sizes,new_size,cnt[maxn],inp[maxn],typ[maxn],sum[maxn]; bool cmp(Node a,Node b) { return (belong[a.l]^belong[b.l]?belong[a.l]<belong[b.l]:((belong[a.l]&1)?a.r<b.r:a.r>b.r)); } int main() { int n,m; scanf("%d%d",&n,&m); sizes=sqrt(n); new_size=ceil((double)n/sizes); for(int i=1; i<=n; ++i) arr[i]=inp[i]=read(); sort(inp+1,inp+1+n); int tot=unique(inp+1,inp+1+n)-inp-1; for(int i=1; i<=n; ++i) { typ[i]=lower_bound(inp+1,1+inp+tot,arr[i])-inp; } for(int i=1;i<=m;++i) { scanf("%d%d",&node[i].l,&node[i].r); node[i].id=i; } for(int i=1;i<=new_size;++i) { for(int j=(i-1)*sizes+1;j<=i*sizes;++j) { belong[j]=i; } } sort(node+1,node+1+m,cmp); int l=1,r=0,maxx=0; for(int i=1;i<=m;++i) { int start=node[i].l,last=node[i].r; while(l<start) { if(cnt[typ[l]]==maxx && sum[cnt[typ[l]]]==1) { maxx--; } sum[cnt[typ[l]]]--; cnt[typ[l]]--; sum[cnt[typ[l]]]++; l++; } while(l>start) { l--; sum[cnt[typ[l]]]--; cnt[typ[l]]++; sum[cnt[typ[l]]]++; maxx=max(maxx,cnt[typ[l]]); } while(r>last) { if(cnt[typ[r]]==maxx && sum[cnt[typ[r]]]==1) { maxx--; } sum[cnt[typ[r]]]--; cnt[typ[r]]--; sum[cnt[typ[r]]]++; r--; } while(r<last) { r++; sum[cnt[typ[r]]]--; cnt[typ[r]]++; sum[cnt[typ[r]]]++; maxx=max(maxx,cnt[typ[r]]); } ans[node[i].id]=maxx; } for(int i=1;i<=m;++i) printf("%d ",-ans[i]); return 0; }
题目背景
在那遥远的西南有一所学校,
/*被和谐部分*/
然后去参加该省省选虐场,
然后某蒟蒻不会做,所以也出了一个字符串题:
题目描述
给你一个字符串 a,每次询问一段区间的贡献。
贡献定义:
每次从这个区间中拿出一个字符 x ,然后把 x 从这个区间中删除,直到区间为空。你要维护一个集合 S。
- 如果 S 为空,你 rp 减 1。
- 如果 S 中有一个元素不小于 x,则你 rp 减 1,清空 S。
- 之后将 x 插入 S。
由于你是大爷,平时做过的题考试都会考到,所以每次询问你搞完这段区间的字符之后最多还有多少 rp?rp 初始为 0。
询问之间不互相影响~
输入格式
第一行两个整数 n,m,表示字符串长度与询问次数。
之后一行 n 个数,第 i 个整数表示给出的字符串的第 i 个字符 xi。
接下来 m 行,每行两个整数 l,r,表示一次询问的区间。
输出格式
对于每次询问,输出一行一个整数表示答案。
输入输出样例
说明/提示
数据规模与约定
- 对于 10% 的数据,是样例。
- 对于另外 10% 的数据,保证 n,m≤100;
- 对于另外 10% 的数据,保证 n,m≤103;
- 对于另外 10% 的数据,保证 n,m≤104;
- 对于另外 10% 的数据,保证 n,m≤105;
- 对于 100% 的数据,1≤n,m≤2×105,1≤ai≤109,1≤l,r≤n。