乙個簡單的詢問 HYSBZ 5016

2021-09-26 00:09:30 字數 2064 閱讀 8210

給你乙個長度為n的序列ai,1≤i≤n和q組詢問,每組詢問讀入l1,r1,l2,r2,需輸出

get(l,r,x)表示計算區間[l,r]中,數字x出現了多少次。

input

第一行,乙個數字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的最大值

output

對於每組詢問,輸出一行乙個數字,表示答案

sample input

51 1 1 1 1

21 2 3 4

1 1 4 4

思路:

我們可以看到這個式子get(l,r,x),我們可以將其分解得到

get(l,r,x)=get(1,r,x)-get(1,l,r),所以我們令s(i)=get(1,i,x);

那麼

又因為所以ans

仔細看分子,實際上就是四個區間中x的數量的平方

(r1,l2),(l1,r2),(l1,l2),(r1,r2)

我們只需要用莫隊維護一下區間x的個數的平方就可以了

**如下:…(* ̄0 ̄)ノ

#include

#include

#include

#include

#include

#define ll long long

using namespace std;

const

int mx=

5e4+10;

ll s[mx]

,ans[mx]

,c[mx]

,sum;

//分別為統計區間每個數個數,結果,輸入,和

int tot=

0,cnt;

//分別為p陣列的大小和分塊的大小

struct nodebp[mx<<2]

;bool cmp

(nodeb a,nodeb b)

//分塊排序

void

add(

int k)

//增加操作

void

del(

int k)

//刪除操作

void

put(

int x,

int y,

int a,

int b)

//這裡就是將每次查詢得到四個區間分別弄出來

intmain()

sort

(p+1

,p+1

+tot,cmp)

;//排序

memset

(s,0

,sizeof

(s))

;memset

(ans,0,

sizeof

(ans));

int l=

1,r=0;

sum=0;

for(

int i=

1;i<=tot;i++

)//這裡要記住,add一定是要先增或減,del要後操作

for(

int i=

1;i<=m;i++

)printf

("%lld\n"

,ans[i]

>>1)

;//最後輸出記得除2

return0;

}

bzoj5016 乙個簡單的詢問

這種不可直接做的問題 資料範圍又很小 考慮莫隊 但是,l1,l2,r1,r2四維?考慮把詢問二維差分!f a,b 表示,詢問 1,a 1,b 的答案 所以,ans l1,r1,l2,y2 f r1,r2 f l1 1,r2 f r1,l2 1 f l1 1,l2 1 正確性的話,考慮每乙個種類k被統...

SNOI2017 乙個簡單的詢問

給定乙個長度為 n n le50000 的序列 a 1 le a i le n 定義 operatorname l,r,x 為區間 a 中 x 的出現次數。m m le50000 次詢問,每次給出 l 1,r 1,l 2,r 2 求 sum operatorname l 1,r 1,x cdot o...

洛谷P5268 乙個簡單的詢問

傳送門 to luogu 首先它是個莫隊的題。為什麼?我也不知道 但是莫隊只能處理兩個變數的詢問 並且任意乙個變數的移動對答案的影響可以快速計算,一般是 o 1 mathcal o 1 o 1 所以只好把這個式子變換一下。記 f m x j 1 m aj x f m,x sum a j x f m,...