zoukankan      html  css  js  c++  java
  • 【bzoj5016】[Snoi2017]一个简单的询问 莫队算法

    题目描述

    给你一个长度为N的序列ai,1≤i≤N和q组询问,每组询问读入l1,r1,l2,r2,需输出
    get(l,r,x)表示计算区间[l,r]中,数字x出现了多少次。

    输入

    第一行,一个数字N,表示序列长度。
    第二行,N个数字,表示a1~aN
    第三行,一个数字Q,表示询问个数。
    第4~Q+3行,每行四个数字l1,r1,l2,r2,表示询问。
    N,Q≤50000
    N1≤ai≤N
    1≤l1≤r1≤N
    1≤l2≤r2≤N
    注意:答案有可能超过int的最大值

    输出

    对于每组询问,输出一行一个数字,表示答案

    样例输入

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

    样例输出

    4
    1


    题解

    莫队算法

    (为了方便,以下使用$S_x(l,r)$代替$get(l,r,x)$)

    题目一眼莫队,不过由于一个询问有4个参数,不能直接处理。

    考虑将询问拆成前缀相减的形式,即:

    $ sumlimits_xS_x(l_1,r_1)·S_x(l_2,r_2)\=sumlimits_{x}(S_x(1,r_1)-S_x(1,l_1-1))·(S_x(1,r_2)-S_x(1,l_2-1))\=sumlimits_{x}(S_x(1,r_1)·S_x(1,r_2)-S_x(1,l_1-1)·S_x(1,r_2)--S_x(1,r_1)·S_x(1,l_2-1)+S_x(1,l_1-1)·S_x(1,l_2-1))\=Q(r_1,r_2)-Q(l_1-1,r_2)-Q(r_1,l_2-1)+Q(l_1-1,l_2-1)$

    其中:

    $Q(a,b)=sumlimits_{x}S_x(1,a)·S_x(1,b)$

    于是就可以把每个询问拆成4个,使用莫队算法分别计算对每个答案的贡献即可。

    注意当$a$或$b$中某一个为0时的情况需要过滤掉,否则会加入不存在的位置导致挂掉。

    时间复杂度$O(nsqrt{4m})$

    #include <cmath>
    #include <cstdio>
    #include <algorithm>
    #define N 50010
    using namespace std;
    typedef long long ll;
    int si , v[N] , cl[N] , cr[N] , tot;
    ll ans[N];
    struct data
    {
    	int l , r , flag , id;
    	data() {}
    	data(int a , int b , int c , int d) {l = min(a , b) , r = max(a , b) , flag = c , id = d;}
    	bool operator<(const data &a)const {return (l - 1) / si == (a.l - 1) / si ? r < a.r : (l - 1) / si < (a.l - 1) / si;}
    }a[N << 2];
    int main()
    {
    	int n , m , i , x1 , y1 , x2 , y2 , lp = 0 , rp = 0;
    	ll now = 0;
    	scanf("%d" , &n) , si = (int)sqrt(n);
    	for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &v[i]);
    	scanf("%d" , &m);
    	for(i = 1 ; i <= m ; i ++ )
    	{
    		scanf("%d%d%d%d" , &x1 , &y1 , &x2 , &y2) , a[++tot] = data(y1 , y2 , 1 , i);
    		if(x1 > 1) a[++tot] = data(x1 - 1 , y2 , -1 , i);
    		if(x2 > 1) a[++tot] = data(y1 , x2 - 1 , -1 , i);
    		if(x1 > 1 && x2 > 1) a[++tot] = data(x1 - 1 , x2 - 1 , 1 , i);
    	}
    	sort(a + 1 , a + tot + 1);
    	for(i = 1 ; i <= tot ; i ++ )
    	{
    		while(lp < a[i].l) lp ++ , now += cr[v[lp]] , cl[v[lp]] ++ ;
    		while(rp < a[i].r) rp ++ , now += cl[v[rp]] , cr[v[rp]] ++ ;
    		while(lp > a[i].l) cl[v[lp]] -- , now -= cr[v[lp]] , lp -- ;
    		while(rp > a[i].r) cr[v[rp]] -- , now -= cl[v[rp]] , rp -- ;
    		ans[a[i].id] += a[i].flag * now;
    	}
    	for(i = 1 ; i <= m ; i ++ ) printf("%lld
    " , ans[i]);
    	return 0;
    }
    

     

  • 相关阅读:
    有关mysql数据库的编码
    成功启动了Apache却没有启动apache服务器
    遍历元素绑定事件时作用域是怎么回事啊,为什么要用this关键字,而直接使用元素本身就不行?
    js中给函数传参函数时,函数加括号与不加括号的区别
    win64安装及配置apache+php+mysql
    ubuntu 12.04 安装nginx
    ubuntu下怎么显示右上角的小键盘
    ubuntu12.04安装Vmware Tools
    PyCharm教程
    jira使用指南
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7597573.html
Copyright © 2011-2022 走看看