給你乙個長度為 \(n\) 的序列 \(a_i\),\(1\leq i\leq n\),和 \(q\) 組詢問,每組詢問讀入 \(l_1,r_1,l_2,r_2\),需輸出
\(\sum\limits_^\infty \text(l_1,r_1,x)\times \text(l_2,r_2,x)\)。
\(\text(l,r,x)\) 表示計算區間 \([l,r]\) 中,數字 \(x\) 出現了多少次。
第一行,乙個數字 \(n\),表示序列長度。
第二行,\(n\) 個數字,表示 \(a_1\sim a_n\)。
第三行,乙個數字 \(q\),表示詢問個數。
第 \(4\sim q+3\) 行,每行四個數字 \(l_1,r_1,l_2,r_2\),表示詢問。
對於每組詢問,輸出一行乙個數字,表示答案。
51 1 1 1 1
21 2 3 4
1 1 4 441
對於 \(20\%\) 的資料,\(1\leq n,q\leq 1000\);
對於另外 \(30\%\) 的資料,\(1\leq a_i\leq 50\);
對於 \(100\%\) 的資料,\(n,q\leq 50000\),\(1\leq a_i\leq n\),\(1\leq l_1\leq r_1\leq n\),\(1\leq l_2\leq r_2\leq n\)。
資料範圍與原題相同,但測試資料由 libreoj 自製,並非原資料。
注意:答案有可能超過int
的最大值。
區間問題往往可以想到字首和。如果想用字首和的形式表示這個式子,那麼可以按照如下過程化簡:
\[\begin \sum_^ get(l_1, r_1, x) \times get(l_2, r_2, x) = &\sum_^ get(0, r_1, x) \times get(0, r_2, x)\\ - &\sum_^ get(0, l_1-1, x) \times get(0, r_2, x)\\ - &\sum_^ get(0, r_1, x) \times get(0, l_2-1, x) \\ + &\sum_^ get(0, l_1-1, x) \times get(0, l_2-1, x) \end
\]這樣,我們就把乙個詢問拆成了4個可以用莫隊維護的詢問。對於每乙個詢問,維護 \(num[0][x]\) 表示在區間 \([1,l]\) 中 \(x\) 出現了多少次,\(num[1][x]\) 表示區間 \([1,r]\) 中 \(x\) 出現了多少次。那麼答案就是 \(\sum\limits_^\infty num[0][x]*num[1][x]\) 。至於修改操作,可以這麼看:假設乙個數原來是 \(a*b\) ,現在要把它變成 \((a+1)*b\) ,其實就相當於在原來的基礎上加上乙個 \(b\) 。這裡也是同理。
#include #include #include #include #define int long long
#define n 50002
using namespace std;
struct queryq[4*n];
int n,m,i,a[n],b[n],gap,cnt,num[2][n],sum,ans[4*n],l,r;
int read()
return w;
}int my_comp(const query &x,const query &y)
for(i=1;i<=cnt;i+=4) printf("%lld\n",ans[i]-ans[i+1]-ans[i+2]+ans[i+3]);
return 0;
}
洛谷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,...
洛谷P2709 小B的詢問
傳送門 題目描述 小b有乙個序列,包含n個1 k之間的整數。他一共有m個詢問,每個詢問給定乙個區間 l.r 求sigma c i 2 的值,其中i的值從1到k,其中c i 表示數字i在 l.r 中的重複次數。小b請你幫助他回答詢問。輸入輸出格式 輸入格式 第一行,三個整數n m k。第二行,n個整數...
洛谷P2709 小B的詢問
題目描述 小b有乙個序列,包含n個1 k之間的整數。他一共有m個詢問,每個詢問給定乙個區間 l.r 求sigma c i 2 的值,其中i的值從1到k,其中c i 表示數字i在 l.r 中的重複次數。小b請你幫助他回答詢問。輸入輸出格式 輸入格式 第一行,三個整數n m k。第二行,n個整數,表示小...