Strange Queries(莫队)

题目

You are given an array with n integers a1, a2, ..., an, and q queries to answer.

Each query consists of four integers l1, r1, l2 and r2. Your task is to count the number of pairs of indices (i, j) satisfying the following conditions:

ai = aj
l1 ≤ i ≤ r1
l2 ≤ j ≤ r2
Input
The first line of the input contains an integer n (1 ≤ n ≤ 50 000) — the size of the given array.

The second line contains n integers a1, a2, ..., an (1 ≤ ai ≤ n).

The third line contains an integer q (1 ≤ q ≤ 50 000) — the number of queries.

Each of the next q lines contains four integers l1, r1, l2, r2 (1 ≤ l1 ≤ r1 ≤ n, 1 ≤ l2 ≤ r2 ≤ n), describing one query.

Output
For each query count the number of sought pairs of indices (i, j) and print it in a separate line.

Examples
Input
7
1 5 2 1 7 2 2
8
1 3 4 5
2 3 5 7
1 4 3 7
2 6 4 7
1 6 2 5
3 3 6 7
4 5 1 4
2 3 4 5
Output
1
2
5
6
6
2
2
0

题目:

您将获得一个包含n个整数a1,a2,...,an和q查询的数组。

每个查询由四个整数l1,r1,l2和r2组成。您的任务是计算满足以下条件的索引对(i,j)的数量:

\(a_i = a_j\)
L1 ≤ i ≤ R1
L2 ≤ j ≤ R2

输入

输入的第一行包含一个整数n(1≤N≤50 000) -给定阵列的大小。

第二行包含n个整数a1,a2,...,a(1≤ai≤n)。

第三行包含一个整数q(1≤q≤50000) - 查询数。

接下来的q行中的每一行包含四个整数l1,r1,l2,r2(1≤l1≤r1≤n,1≤l2≤r2≤n),描述一个查询。

输出

对于每个查询计数所寻求的索引对(i,j)的数量,并将其打印在单独的行中。

示例输入

7 
1 5 2 1 7 2 2 
8 
1 3 4 5 
2 3 5 7 
1 4 3 7 
2 6 4 7 
1 6 2 5 
3 3 6 7 
4 5 1 4 
2 3 4 5 

示例输出

1 
2 
5 
6 
6 
2 
2 
0

仔细观察题目我们不难发现这题我们需要维护两个区间内元素的出现次数

嗯?这不是裸裸的莫队吗?等等,两个\(50000\)的区间,我不敲时谁敲时?

这谁做得出啊??干脆维护一个区间算了,暴力枚举第二个区间算了!!

于是某年某月某日某蒟蒻以2000毫秒的好成绩卡了过去:

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>

#define db double
#define inf 0x7fffffff
#define rg register int

using namespace std;

struct su{
    int l,r,ll,rr,t;
}k[50001];

long long now;
int z[50001];
int s[50001];
int tot[50001];
int tot2[50001];
long long ans[50001];
int n,m,q,f,l=1,r,ll=1,rr;

inline int qr(){
    char ch;
    while((ch=getchar())<'0'||ch>'9');
    int res=ch^48;
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+(ch^48);
    return res;
}

inline bool cmp(su x,su y){
    return z[x.l]==z[y.l]?x.r<y.r:x.l<y.l;
}

inline void add(int x,int y){
    now-=(long long)tot2[x]*tot[x];
    tot[x]+=y;
    now+=(long long)tot2[x]*tot[x];
}

inline void add2(int x,int y){
    now-=(long long)tot[x]*tot2[x];
    tot2[x]+=y;
    now+=(long long)tot[x]*tot2[x];
}

int main(){
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    n=qr();
    f=sqrt(n-1)+1;
    for(rg i=1;i<=n;++i) s[i]=qr();
    for(rg i=1,j=1;i<=n;++i)
        z[i]=i%f==0?j++:j;
    m=qr();
    for(rg i=1;i<=m;++i){
        k[i].l=qr();
        k[i].r=qr();
        k[i].ll=qr();
        k[i].rr=qr();
        k[i].t=i;
    }
    sort(k+1,k+m+1,cmp);
    for(rg i=1;i<=m;++i){
        while(l<k[i].l)add(s[l],-1),++l;
        while(k[i].l<l)add(s[l-1],1),--l;
        while(r<k[i].r)add(s[r+1],1),++r;
        while(k[i].r<r)add(s[r],-1),--r;
        while(ll<k[i].ll)add2(s[ll],-1),++ll;
        while(k[i].ll<ll)add2(s[ll-1],1),--ll;
        while(rr<k[i].rr)add2(s[rr+1],1),++rr;
        while(k[i].rr<rr)add2(s[rr],-1),--rr;
        ans[k[i].t]=now;
    }
    for(rg i=1;i<=m;++i)
        printf("%lld\n",ans[i]);
    return 0;
}

转载于:https://www.cnblogs.com/812-xiao-wen/p/10122893.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值