P3709 大爷的字符串题 莫队

题目链接

 

题意:

就是让你找那个众数在询问的区间内出现了多少次,就比如样例:

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,71,1,1,2,2,4,5,6,6,7

我们把它排成一段一段的递增序列可以使rprp掉的最少

就变成了1,2,4,5,6,7,1,2,6,11,2,4,5,6,7,1,2,6,1共掉3点rprp

然后发现递增序列的个数就等于区间众数的出现次数

 

求众数,我们就需要维护最大值(之前做了一道回滚莫队,我一看维护最大值就感觉是回滚莫队,难搞 -_-)。普通莫队就可以解决它

我们用一个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\n",-ans[i]);
    return 0;
}

 

 

题目背景

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

/*被和谐部分*/

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

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

题目描述

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

贡献定义:

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

  • 如果 SS 为空,你 rp 减 11
  • 如果 SS 中有一个元素不小于 xx,则你 rp 减 11,清空 SS
  • 之后将 xx 插入 SS

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

询问之间不互相影响~

输入格式

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

之后一行 nn 个数,第 ii 个整数表示给出的字符串的第 ii 个字符 x_ixi

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

输出格式

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

输入输出样例

输入 #1
3 3
3 3 3
3 3
3 3
3 3
输出 #1
-1
-1
-1

说明/提示

数据规模与约定

  • 对于 10\%10% 的数据,是样例。
  • 对于另外 10\%10% 的数据,保证 n,m \le 100n,m100
  • 对于另外 10\%10% 的数据,保证 n,m \le 10^3n,m103
  • 对于另外 10\%10% 的数据,保证 n,m \le 10^4n,m104
  • 对于另外 10\%10% 的数据,保证 n,m \le 10^5n,m105
  • 对于 100\%100% 的数据,1 \leq n,m \le 2 \times10^51n,m2×1051 \leq a_i \leq 10^91ai1091 \leq l, r \leq n1l,rn
posted @ 2020-09-25 15:50  kongbursi  阅读(86)  评论(0编辑  收藏  举报