区间求和(莫队算法)
链接:https://ac.nowcoder.com/acm/contest/1085/G
来源:牛客网
小sun最近突然对区间来了兴趣,现在他有这样一个问题想问问你:
给你n个数,每个数为ai,现在有m个询问,每个询问l,r,需要求出:
链接:https://ac.nowcoder.com/acm/contest/1085/G
来源:牛客网
输入描述:
第一行,两个整数n,m
第二行,总共n个数,代表这个数列
接下来m行,每行两个整数l,r,代表一个询问
输出描述:
输出总共m行,对于每个询问,输出这个询问对应的答案
备注:
1≤n,m≤1e5
1≤ai≤1e5
1≤l,r≤n
经典莫队算法:维护区间某个数的出现次数
但是这个让求的是区间内的ai*num[i]
如果区间内有两个5就是加上5*2+5*2
不是简单的加a[i]
#include<iostream> #include<algorithm> using namespace std; const int maxn=5e5+100; typedef long long ll; int n,m; int a[maxn]; ll ans[maxn]; int vis[maxn]; struct node{ int l,r; int id; }t[maxn]; int mp[maxn],block,belong[maxn]; bool cmp(node x,node y){ if(belong[x.l]!=belong[y.l]){ return belong[x.l]<belong[y.l]; } else{ if(belong[x.l]&1){ return x.r<y.r; } else{ return x.r>y.r; } } } ll res; void remove(int pos){ res-=1ll*a[pos]*vis[a[pos]]*vis[a[pos]];//先把之前的权值减去在加上之后的权值 vis[a[pos]]--; res+=1ll*a[pos]*vis[a[pos]]*vis[a[pos]]; } void add(int pos){ res-=1ll*a[pos]*vis[a[pos]]*vis[a[pos]]; vis[a[pos]]++; res+=1ll*a[pos]*vis[a[pos]]*vis[a[pos]]; } int main(){ scanf("%d%d",&n,&m); block=sqrt(n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); belong[i]=(i-1)/block+1; }//分块处理 for(int i=1;i<=m;i++){ scanf("%d%d",&t[i].l,&t[i].r); t[i].id=i; } sort(t+1,t+m+1,cmp); int l=1,r=0; int ql,qr; for(int i=1;i<=m;i++){ ql=t[i].l,qr=t[i].r; while(l<ql){ remove(l++); } while(l>ql){ add(--l); } while(r>qr){ remove(r--); } while(r<qr){ add(++r); } ans[t[i].id]=res; } for(int i=1;i<=m;i++){ printf("%lld\n",ans[i]); } }