標籤:blog os for io 演算法 div
思路:莫隊演算法,離線操作,將所有詢問的左端點進行分塊(分成sqrt(n) 塊每塊sqrt(n)個),用左端點的塊號進行排序小的在前,塊號相等的,右端點小的在前面。 這樣要是兩個相鄰的查詢在同一塊內左端點每次最多移動sqrt(n) n次的話效率為nsqrt(n) ,對於同一塊內右端點為有序的那麼最多移動 n次 。總的效率為nsqrt(n) 。 要是相鄰的查詢不同塊 最壞效率為O(n) 因為塊最多為sqrt(n)個那麼壞效率也為nsqrt(n)。 總的效率就為nsqrt(n)
#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include <iostream>#define N 200010#define LL __int64using namespace std;struct node {int l, r, id;int pid;} s[N];inline bool cmp(node a, node b) {return a.id < b.id || a.id == b.id && a.r < b.r;}int a[N];LL ans[N];int cnt[1000100];LL sum = 0;inline void add(LL x) {sum += x * (cnt[x] << 1 | 1);cnt[x]++;}inline void dec(LL x) {sum += x * (1 - (cnt[x] << 1));cnt[x]--;}int main() {int i, j, k, n, m, one;memset(cnt, 0, sizeof(cnt));scanf("%d%d", &n, &m);one = sqrt(n * 1.0);for (int i = 1; i <= n; ++i)scanf("%d", &a[i]);for (int i = 0; i < m; ++i) {scanf("%d%d", &s[i].l, &s[i].r);s[i].id = s[i].l / one;s[i].pid=i;}sort(s, s + m, cmp);int l, r;l = s[0].l;r = s[0].r;for (int i = s[0].l; i <= s[0].r; ++i)add(a[i]);ans[s[0].pid]=sum;for (i = 1; i < m; ++i) {while(r<s[i].r)add(a[++r]);while(r>s[i].r)dec(a[r--]);while(l<s[i].l)dec(a[l++]);while(l>s[i].l)add(a[--l]);ans[s[i].pid]=sum;}for(int i=0;i<m;++i)printf("%I64d\n",ans[i]);return 0;}