莫队(感觉就是niubi的排序.)
将序列分成相等大小的若干块,每块大小为p,(p通常取sqrt(n)) 将query按下列方式离线处理后 复杂度神奇的达到了O(nsqrt(n))左右.
1):排序,以左段点所在的块为第一关键字,以右端点为第二关键字
2):从左往右处理询问(离线)
3):已知当前[l,r]的答案后,不断调整l,r的位置并同时修改
复杂度分析: 其实就是l,r总共的移动次数. 先考虑某一块的l,r移动次数.
该块r是递增的 最多向后移动n次,
该块l最坏情况下每次移动p个单位 该块询问中总共移动|qi|*p次 (|qi|为该块询问次数)
现在有n/p块
r总共移动n*n/p次,L总共移动p*|q1+q2+..qk|=p*n次.
剩下的就是:从当前块到下一块的移动次数: r最坏移动向左移动n个单位,总共移动n/p次,l最坏移动2*p个单位,总共移动2*p*n/p次.
总的时间复杂度为O(n*n/p+p*n+n/p+2*n)=O(n*n/p+p*n) 此时p取sqrt(n)即可达到O(nsqrt(n))的复杂度.
n,Q<=2e5,a[i]<=1e6,Q次询问,每次询问[l,r]的价值为多少?
按Mo's order离线后从,cnt[x]统计当前区间每个x的出现次数.
当增加某个x,先减去x*cnt[x]*cnt[x],将cnt[x]++后,在加回x*cnt[x]*cnt[x],总共增加2cnt[x]+1.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
struct node{
int l,r,id;
ll ans;
}q[N];
int n,Q,pos[N],a[N],cnt[1000005];
bool cmp(node a,node b)
{
if(pos[a.l]==pos[b.l])
return a.r<b.r;
return a.l<b.l;
}
ll res,ans[N];
void init()
{
res=0;
int block=sqrt(n);
for(int i=1;i<=n;i++)
pos[i]=(i-1)/block+1;
}
void add(int i)
{
ll x=cnt[a[i]];
res+=(2ll*x+1ll)*a[i];
cnt[a[i]]++;
}
void del(int i)
{
ll x=cnt[a[i]];
res+=(-2ll*x+1ll)*a[i];
cnt[a[i]]--;
}
void solve()
{
for(int i=1,l=1,r=0;i<=Q;i++)
{
for(;r<q[i].r;r++)
add(r+1);
for(;r>q[i].r;r--)
del(r);
for(;l<q[i].l;l++)
del(l);
for(;l>q[i].l;l--)
add(l-1);
ans[q[i].id]=res;
}
}
int main()
{
scanf("%d%d",&n,&Q);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
init();
for(int i=1;i<=Q;i++)
scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
sort(q+1,q+Q+1,cmp);
solve();
for(int i=1;i<=Q;i++)
printf("%I64d\n",ans[i]);
return 0;
}
CF 220B
题意:长度为n的序列a,Q次询问:求[l,r]内有多少个数x正好出现x次,x属于[a[l]..a[r]].
n,m<=1e5,a[i]<=1e9
莫队排序后,离线
离散化一下a[i] 统计第x小的出现频率,第x小的出现b[x]次时累加答案.(记得去重)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
struct node{
int l,r,id;
ll ans;
}q[N];
vector<int> b;
int n,Q,pos[N],a[N],v[N];
int cnt[N];
bool cmp(node a,node b)
{
if(pos[a.l]==pos[b.l])
return a.r<b.r;
return a.l<b.l;
}
ll res,ans[N];
void init()
{
res=0;
int block=sqrt(n);
for(int i=1;i<=n;i++)
pos[i]=(i-1)/block+1;
}
void add(int i)
{
int x=v[i];
if(cnt[x]==b[x])//µÚxСµÄ³öÏÖ´ÎÊýҪΪb[x]
res--;
cnt[x]++;
if(cnt[x]==b[x])
res++;
}
void del(int i)
{
int x=v[i];
if(cnt[x]==b[x])
res--;
cnt[x]--;
if(cnt[x]==b[x])
res++;
}
void solve()
{
for(int i=1,l=1,r=0;i<=Q;i++)
{
for(;r<q[i].r;r++)
add(r+1);
for(;r>q[i].r;r--)
del(r);
for(;l<q[i].l;l++)
del(l);
for(;l>q[i].l;l--)
add(l-1);
ans[q[i].id]=res;
}
}
int getid(int x)
{
return lower_bound(b.begin(),b.end(),x)-b.begin();
}
int main()
{
scanf("%d%d",&n,&Q);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),b.push_back(a[i]);
sort(b.begin(),b.end());
b.erase(unique(b.begin(),b.end()),b.end());
for(int i=1;i<=n;i++)
v[i]=getid(a[i]);//cout<<v[i]<<' ';
init();
for(int i=1;i<=Q;i++)
scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
sort(q+1,q+Q+1,cmp);
solve();
for(int i=1;i<=Q;i++)
printf("%I64d\n",ans[i]);
return 0;
}