1. 程式人生 > >luogu 2709 小B的詢問 莫隊

luogu 2709 小B的詢問 莫隊

turn 區間 span || efi OS type http int

題目鏈接

Description

小B有一個序列,包含\(N\)\(1-K\)之間的整數。他一共有\(M\)個詢問,每個詢問給定一個區間\([L..R]\),求\(\sum_{i=1}^{K}c_i^2\),其中\(c_i\)表示數字\(i\)\([L..R]\)中的重復次數。小B請你幫助他回答詢問。

思路

裸的莫隊。

\(cnt[x]\)記錄\(x\)的出現次數,增量為\((cnt[x]+1)^2-cnt[x]^2=2*cnt[x]+1\)\(-2*cnt[x]+1\).

Code

#include <bits/stdc++.h>
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i) #define dF(i, a, b) for (int i = (a); i > (b); --i) #define dF2(i, a, b) for (int i = (a); i >= (b); --i) #define maxn 50010 using namespace std; typedef long long LL; struct node { int l, r,id; }a[maxn]; LL temp; int n,m,k,blo,bl[maxn],v[maxn]; LL cnt[maxn],ans[maxn]; inline
bool cmp(node&u, node& v) { return bl[u.l]<bl[v.l] || (bl[u.l]==bl[v.l]&&u.r<v.r); } inline void upd(int x, int delta) { temp += delta*(cnt[x]<<1)+1; cnt[x]+=delta; } int main() { scanf("%d%d%d", &n,&m,&k); blo = sqrt(n); F(i, 0, n) scanf("
%d", &v[i]), bl[i]=i/blo; F(i, 0, m) { scanf("%d%d", &a[i].l, &a[i].r); --a[i].l, --a[i].r; a[i].id = i; } sort(a,a+m,cmp); int l=0, r=-1; temp=0; F(i, 0, m) { while (r<a[i].r) upd(v[++r],1); while (r>a[i].r) upd(v[r--],-1); while (l>a[i].l) upd(v[--l],1); while (l<a[i].l) upd(v[l++],-1); ans[a[i].id] = temp; } F(i, 0, m) printf("%lld\n", ans[i]); return 0; }

luogu 2709 小B的詢問 莫隊