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;
    }
    

     

  • 相关阅读:
    CF1051F The Shortest Statement 题解
    CF819B Mister B and PR Shifts 题解
    HDU3686 Traffic Real Time Query System 题解
    HDU 5969 最大的位或 题解
    P3295 萌萌哒 题解
    BZOJ1854 连续攻击游戏 题解
    使用Python编写的对拍程序
    CF796C Bank Hacking 题解
    BZOJ2200 道路与航线 题解
    USACO07NOV Cow Relays G 题解
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7597573.html
Copyright © 2011-2022 走看看