gym-101138D(后缀和,莫队算法,容斥原理,好题)

这道题目要求在给定的数组中,根据一系列查询条件计算满足条件的数对数量。通过应用莫队算法,可以高效地处理每个查询,维护后缀数组中相同元素的计数,从而计算出每个查询的答案。

D. Strange Queries
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

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

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

  1. ai = aj
  2. l1 ≤ i ≤ r1
  3. 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 l1r1l2r2 (1 ≤ l1 ≤ r1 ≤ n1 ≤ 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

题意简明。


题解:

使用莫队算法

假设当前左右指针分别为l和r,一共n个数

对于指针l,维护一个后缀[l,n],算这个后缀每个数出现次数。

对于指针r,维护一个后缀(r,n]算这个后缀每个数出现次数。

对区间[l,r)维护[l,n]和[r,n]中相等的数的对数。

假设区间[l,r)的答案为f(l,r).

那么,对于询问l1,r1,l2,r2, 答案是f(l1,l2)-f(l1,r2+1)-f(r1+1,l2)+f(r1+1,r2+1).

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<cmath>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const int inf=0x3fffffff;
const ll mod=1000000007;
const int maxn=50000+100;
int unit;
struct node
{
    int l,r,id,k;
    bool operator <(const node&b) const{
        if(l/unit==b.l/unit) return r<b.r;
        else return l/unit<b.l/unit;
    }
    node(int x=0,int y=0):l(x),r(y) {}
}a[maxn*4];
int m=0,n;
ll ans[maxn];
int num[maxn];
ll cnt[2][maxn];
ll res;
void solve()
{
    sort(a,a+m);
    memset(cnt,0,sizeof(cnt));
    memset(ans,0,sizeof(ans));
    int l=n+1,r=n+1;   //
    res=0;
    rep(i,0,m)
    {
        while(l<a[i].l)
        {
            res-=1ll*cnt[0][num[l]]*cnt[1][num[l]];
            cnt[0][num[l]]--;
            res+=1ll*cnt[0][num[l]]*cnt[1][num[l]];
            l++;
        }
        while(l>a[i].l)
        {
            l--;
            res-=1ll*cnt[0][num[l]]*cnt[1][num[l]];
            cnt[0][num[l]]++;
            res+=1ll*cnt[0][num[l]]*cnt[1][num[l]];
        }
        while(r<a[i].r)
        {
            res-=1ll*cnt[1][num[r]]*cnt[0][num[r]];
            cnt[1][num[r]]--;
            res+=1ll*cnt[1][num[r]]*cnt[0][num[r]];
            r++;
        }
        while(r>a[i].r)
        {
            r--;
            res-=1ll*cnt[1][num[r]]*cnt[0][num[r]];
            cnt[1][num[r]]++;
            res+=1ll*cnt[1][num[r]]*cnt[0][num[r]];
        }
        ans[a[i].id]+=a[i].k*res;
    }
}
int main()
{
    scanf("%d",&n);
    unit=(int)sqrt(n);
    rep(i,1,n+1) scanf("%d",&num[i]);
    int q;
    scanf("%d",&q);
    rep(i,0,q)
    {
        int l1,r1,l2,r2;
        scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
        r1++,r2++;
        a[m]=node(l1,l2),a[m].id=i,a[m].k=1;
        a[++m]=node(l1,r2),a[m].id=i,a[m].k=-1;
        a[++m]=node(r1,l2),a[m].id=i,a[m].k=-1;
        a[++m]=node(r1,r2),a[m].id=i,a[m].k=1;
        m++;
    }
    solve();
    rep(i,0,q)
    printf("%lld\n",ans[i]);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值