先上题目:链接http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1081
分析:
如果每次查询都需要在遍历计算的话,即复杂度0(n),肯定超时。
那么我们自然会想到,能不能先算好sum[x](a1+a2+....+ax).那么每次遍历我们只需要O(1)复杂度。
sum[x]也是非常容易求的。。。遍历输入的时候 sum[i]=sum[i-1]+a (也算是一道小dp)
这样的话,程序就能动手写了。。
但是还有一些其他的数据结构可以解决这一类问题。
树状数组,线段树。
dp(省时省力)
#include <stdio.h>
#include <stdlib.h>
using namespace std;
const int N=50000+5;
long long sum[N]; //记录每一项前面的和
int main()
{
int a,n;
sum[0]=0;
scanf("%d",&n);
for(int i=1;i<=n;i++) //输出并初始化数据
{
scanf("%d",&a);
sum[i]=sum[i-1]+a;
}
int q,m,l;
scanf("%d",&q);
while(q--)
{
scanf("%d%d",&m,&l);
printf("%lld\n",sum[m+l-1]-sum[m-1]);
}
return 0;
}
树状数组
如果还不清楚树状数组,先学学,很好用的一种数据结构
http://blog.youkuaiyun.com/int64ago/article/details/7429868
学完之后,相信一下程序相当容易了
#include"cstdio" //树状数组
#include"cstdlib"
#include"cstring"
#include"algorithm"
#include"iostream"
using namespace std;
const int N=50000+5;
int a[N];
long long c[N];
int n;
int lowbit(int x) //一分为二的划分
{
return (x&-x);
}
long long sum(int x) //计算(1-x)区间的和
{
long long ans=0;
while(x>0) //向左往上遍历
{
ans+=c[x];
x-=lowbit(x);//遍历左上
}
return ans;
}
void add(int x,int d) //让a[x]增加d
{
while(x<=n) //向右往上增加
{
c[x]+=d;
x+=lowbit(x); //往右上遍历
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) //输出并初始化数据
{
scanf("%d",&a[i]);
add(i,a[i]);
}
int q,m,l;
scanf("%d",&q);
while(q--)
{
scanf("%d%d",&m,&l);
printf("%lld\n",sum(m+l-1)-sum(m-1));
}
return 0;
}
线段树
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
#include"algorithm"
#include"iostream"
#include"math.h"
#include"ctype.h"
const int maxn=50005;
//using namespace std;
long long a[maxn];
long long sum[2*maxn+5];
int n;//数组长度
void Input()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%lld",a+i);
}
void Build(int node,int start,int end)
{//分治法建立线段树 node是线段树起点 [start,end]是数据范围
if(start==end)
{
sum[node]=a[start];
return ;
}
int m=start+(end-start)/2;
Build(node*2,start,m); //左子树
Build(node*2+1,m+1,end); //右子树
sum[node]=sum[node*2]+sum[node*2+1];
}
long long Query(int node,int start,int end,int le,int ri)
{//在区间 [start,end]查找区间[r,l]和(sum),起点node
if(le<=start&&end<=ri) //区间覆盖了 直接选取[start,end]
return sum[node];
//system("pause");
int m=start+(end-start)/2;
long long L=0,R=0;
if(m>=le) L=Query(node*2,start,m,le,ri);
if(m<ri) R=Query(node*2+1,m+1,end,le,ri);
return L+R;
}
void Update(int node,int start,int end,int p,int v)
{
//更新a[p]=v
if(start==end) //只有一个节点
sum[node]=v;
int m=start+(end-start)/2;
if(p<=m)
Update(node*2,start,m,p,v);
else
Update(node*2+1,m+1,end,p,v);
sum[node]=sum[node*2]+sum[node*2+1];
}
void Solve()
{
Build(1,0,n-1);
//for(int i=1;i<=2*n;i++)
// printf("%lld ",sum[i]);
// printf("\n");
int t;
scanf("%d",&t);
while(t--)
{
int le,len;
scanf("%d%d",&le,&len);
long long ans=Query(1,1,n,le,le+len-1);
printf("%lld\n",ans);
}
}
int main()
{
Input();
Solve();
return 0;
}
如有不妥,还望指出。