题目大意:
求一段区间内 出现的数字的次数的三次方的和
思路分析:
这要水过去的题目真是难,各种优化。
不能用map , 要离散化之后 先处理lowerbound。
优化输入。
。
。
时间卡的非常紧。
。
题目直接用莫队水过去。
假设你超时的话,最好还是试试上面三种优化。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <cmath>
#define maxn 100005
using namespace std;
typedef long long LL;
int app[maxn];
int pos[maxn];
int save[maxn];
int x[maxn];
map<int,int>mymap;
struct foo
{
int l,r,index;
LL ans;
bool operator < (const foo &cmp) const
{
if(pos[l]==pos[cmp.l])return r<cmp.r;
return pos[l]<pos[cmp.l];
}
}Q[maxn];
int n;
inline void scanf_(int &num){
char in;
bool neg=false;
while(((in=getchar()) > '9' || in<'0') && in!='-') ;
if(in=='-'){
neg=true;
while((in=getchar()) >'9' || in<'0');
}
num=in-'0';
while(in=getchar(),in>='0'&&in<='9')
num*=10,num+=in-'0';
if(neg)
num=0-num;
}
bool cmp_id(const foo &a,const foo &b)
{
return a.index<b.index;
}
int sz;
void modify(int p,LL &ans,int add)
{
ans-=(LL)app[x[p]]*app[x[p]]*app[x[p]];
app[x[p]]+=add;
ans+=(LL)app[x[p]]*app[x[p]]*app[x[p]];
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
memset(app,0,sizeof app);
int SIZE = (int)sqrt(n*1.0);
for(int i=1;i<=n;i++)
{
scanf_(save[i]);
x[i]=save[i];
pos[i]=(i-1)/SIZE+1;
}
int m;
scanf_(m);
for(int i=0;i<m;i++)
{
scanf_(Q[i].l);
scanf_(Q[i].r);
Q[i].index=i;
}
sort(save+1,save+n+1);
sz=unique(save+1,save+n+1)-save;
for(int i=1;i<=n;i++)
{
x[i] = lower_bound(save+1,save+sz,x[i])-save;
}
sort(Q,Q+m);
LL ans=0;
for(int i=0,l=1,r=0;i<m;i++)
{
if(r<Q[i].r)
{
for(r=r+1;r<=Q[i].r;r++)
modify(r,ans,1);
r--;
}
if(r>Q[i].r)
{
for(;r>Q[i].r;r--)
{
modify(r,ans,-1);
}
}
if(l<Q[i].l)
{
for(;l<Q[i].l;l++)
modify(l,ans,-1);
}
if(l>Q[i].l)
{
for(l=l-1;l>=Q[i].l;l--)
modify(l,ans,1);
l++;
}
if(Q[i].l==Q[i].r)
{
Q[i].ans=1;
continue;
}
Q[i].ans=ans;
}
sort(Q,Q+m,cmp_id);
for(int i=0;i<m;i++)
printf("%I64d\n",Q[i].ans);
}
return 0;
}