zoukankan      html  css  js  c++  java
  • 【luogu1797】faebdc的烦恼-莫队

    题目背景

    鸟哥(faebdc)自从虐暴NOIP2013以来依然勤奋学习,每天上各种OJ刷题,各种比赛更是不在话下。但这天他遇到了一点小小的麻烦……在一届“Orz鸟哥杯”上,题目是在是太多了!足有n道!鸟哥看得头晕眼花,他需要你的帮助。

    每道题都有一个难度值ai,由于wangxz神犇已经提前帮助鸟哥将这些难度值升序排列,所以鸟哥并不想知道哪些题难度低或者高,他只想知道在某些题目ai,ai+1,…,aj中,出现最多的难度值出现的次数(他为啥想知道这么奇葩的东西呢……自己去问)。

    你的任务就是对于鸟哥的每一次询问(i,j),告诉他在从ai到aj这j-i+1道题之中,出现最多的难度值出现的次数(询问共有q次)。

    如果你成功地帮助了鸟哥,鸟哥将会带你通过省选。

    题目描述

    给出一个升序排列的整数数组a1,a2,…an,你的任务是对于鸟哥的一系列询问(i,j),回答ai,ai+1,…aj中出现次数最多的值所出现的次数。

    输入格式

    输入仅包含一组数据。

    第一行为两个整数n,q(1<=n<=100000,1<=q<=200000)。第二行包含n个升序排列的整数a1,a2,…,an(-100000<=ai<=100000),代表每一道题的难度值。以下q行每行包含两个整数i和j(1<=i<=j<=n),代表鸟哥询问的区间。

    输出格式

    对于每次询问,单独输出一行,该行仅有一个整数,表示该区间内出现最多的数值所出现的次数。

    输入输出样例

    输入 #1
    9 1
    
    1 1 1 2 2 3 3 4 4
    
    3 8
    输出 #1
    2
    

    说明/提示

    各个测试点1s

    思路:

      莫队,求众数出现的次数,cnt[]存次数,sum存的是出现次数为某个值得输的个数,如果此时得sum[]为零,则说明把此数删去,没有其他数的众数为此时的答案,答案必须减一,但减一后的sum不用加,因为之前在加到最大值之前加过一次,从之前更新过来的时候,已经加过了。

    代码:

    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #define N 2000000
    using namespace std;
    int a[N],b[N],len,n,m,tot[N];
    int sum[N],cnt[N],ans,Ans[N];
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void add(int x)
    {
    	cnt[x]++;
    	sum[cnt[x]]++;
    	ans=max(ans,cnt[x]);
    }
    void del(int x)
    {
    	sum[cnt[x]]--;
    	if(!sum[cnt[x]])
    		if(ans==cnt[x])
    		{
    			ans--;
    		}
    	cnt[x]--;
    }
    struct node{
    	int l,r,pos,id;
    	bool operator < (const node &a)const
    	{
    		if(pos==a.pos)return r<a.r;
    		return pos<a.pos;
    	}
    }e[N];
    int main()
    {
    	scanf("%d%d",&n,&m);
    	len=sqrt(n);
    	for(int i=1;i<=n;i++)a[i]=b[i]=read();
    	sort(b+1,b+n+1);
    	int le=unique(b+1,b+n+1)-b-1;
    	for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+le+1,a[i])-b;
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%d%d",&e[i].l,&e[i].r);
    		e[i].id=i;
    		e[i].pos=(e[i].l-1)/len+1;
    	}
    	int l=1,r=0;
    	sort(e+1,e+m+1);
    	for(int i=1;i<=m;i++)
    	{
    		while(l<e[i].l)del(a[l++]);
    		while(r>e[i].r)del(a[r--]);
    		while(l>e[i].l)add(a[--l]);
    		while(r<e[i].r)add(a[++r]);
    		Ans[e[i].id]=ans;
    	}
    	for(int i=1;i<=m;i++) printf("%d
    ",Ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
    发送广播重新挂载SD卡,使图库可以及时显示自己保存的图片(无需手机重启)
    Android学习记录(10)—Android之图片颜色处理
    Android学习记录(9)—Android之Matrix的用法
    撕美女衣服应用的原理及做法
    以最省内存的方式把大图片加载到内存及获取Exif信息和获取屏幕高度和宽度的新方法
    通过广播关闭应用程序(每个Activity)和连续点击两次返回键关闭应用程序
    Android有效解决加载大图片时内存溢出的问题
    有关ViewFlipper的使用及设置动画效果的讲解
    Android学习记录(8)—Activity的四种加载模式及有关Activity横竖屏切换的问题
  • 原文地址:https://www.cnblogs.com/yelir/p/11574286.html
Copyright © 2011-2022 走看看