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


    大爷的字符串题

    题目背景

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

    /*被和谐部分*/

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

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

    题目描述

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

    贡献定义:

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

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

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

    询问之间不互相影响~

    输入格式

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

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

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

    输出格式

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

    样例 #1

    样例输入 #1

    3 3
    3 3 3
    3 3
    3 3
    3 3
    
    • 1
    • 2
    • 3
    • 4
    • 5

    样例输出 #1

    -1
    -1
    -1
    
    • 1
    • 2
    • 3

    提示

    数据规模与约定

    • 对于 10 % 10\% 10% 的数据,是样例。
    • 对于另外 10 % 10\% 10% 的数据,保证 n , m ≤ 100 n,m \le 100 n,m100
    • 对于另外 10 % 10\% 10% 的数据,保证 n , m ≤ 1 0 3 n,m \le 10^3 n,m103
    • 对于另外 10 % 10\% 10% 的数据,保证 n , m ≤ 1 0 4 n,m \le 10^4 n,m104
    • 对于另外 10 % 10\% 10% 的数据,保证 n , m ≤ 1 0 5 n,m \le 10^5 n,m105
    • 对于 100 % 100\% 100% 的数据, 1 ≤ n , m ≤ 2 × 1 0 5 1 \leq n,m \le 2 \times10^5 1n,m2×105 1 ≤ a i ≤ 1 0 9 1 \leq a_i \leq 10^9 1ai109 1 ≤ l , r ≤ n 1 \leq l, r \leq n 1l,rn

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

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

    #include
    using namespace std;
    const int N=1e6+10;
    typedef long long ll;
    int n,m,a[N];
    unordered_map<int,int> mp;
    int pos[N],Id=0;
    int c[N],sum=0,num[N],ans[N],L=1,R=0;
    //题意:求区间众数出现的次数的相反数
    struct modui{
    	int l,r,id;
    }s[N];
    bool cmp(modui x,modui y){//按左端点分块,然后在同一个块当中区间右端点要递增
    	if (pos[x.l]!=pos[y.l]) return x.l<y.l;
        if(pos[x.l]&1) return x.r<y.r;//奇偶性优化
    	return x.r>y.r;//都是为了加速
    }
    //c[i]代表i出现的次数
    //num[i]代表出现次数为i的数的个数
    void add(int x){
        //增加一个数,计数器删除原来次数的出现次数,更新现在的次数,更新答案
    	--num[c[x]];
    	++c[x];
    	++num[c[x]];
    	sum=max(sum,c[x]);//如果比当前众数出现的次数多,那么更新答案
    }
    void del(int x){
        //删除一个数,计数器更新原来的出现次数,更新现在的次数,再更新答案
    	--num[c[x]];
    	if(c[x]==sum){
            //如果只有一个众数,删除这个数后,答案必定减1
    		if(num[c[x]]==0) sum--;
    	}
    	--c[x];
    	++num[c[x]];
    	sum=max(sum,c[x]);//如果比当前众数出现的次数多,那么更新答案
    }
    void query(int l,int r,int id){
    	while (L<l) del(a[L++]);//左指针往右移删除
    	while (L>l) add(a[--L]);//左指针往左移加入
    	while (R<r) add(a[++R]);//右指针往右移加入
    	while (R>r) del(a[R--]);//右指针往左移删除
    	ans[id]=sum;//记录答案
    	return;
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	int dis=sqrt(n);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    		if(mp[a[i]]) a[i]=mp[a[i]];//离散化
    		else mp[a[i]]=++Id,a[i]=Id;
    		pos[i]=(i-1)/dis+1;//分块
    	}
    	for(int i=1;i<=m;i++){
    		scanf("%d %d",&s[i].l,&s[i].r);
    		s[i].id=i;
    	}
    	sort(s+1,s+1+m,cmp);
    	for(int i=1;i<=m;i++) query(s[i].l,s[i].r,s[i].id);
    	for(int i=1;i<=m;i++) printf("%d\n",-ans[i]);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
  • 相关阅读:
    [MRCTF2020]Ez_bypass1
    【Python】【源码】SocketIO做一个网络聊天室软件-客户端源码
    牛客 NC25005 [USACO 2008 Ope S]Clear And Present Danger
    测试用例评审的旁观记录
    解决RequestParam.value() was empty on parameter 0
    【GIT版本控制】--高级GIT配置
    宏定义实现二进制数的奇偶位交换
    基于Andriod技术“厕ce”APP-计算机毕业设计源码+LW文档
    Redis4.0源码编译和启动
    为什么感觉越来越穷
  • 原文地址:https://blog.csdn.net/weixin_59624686/article/details/126338236