/*
上次实现了线段树上的求组区间最大值操作,现在来实现求区间和的操作,其实代码兵没哟修改多少
同理,拿走的童鞋请点个赞,谢谢
本文章是个人作品,可以转载,因为你知道的太多了,如果你心情好,带上地址吧,我叫WilliamCode
*/
#include<iostream>
#include<string.h>
#include<stdio.h>
#define lson id*2 //id的左子树编号
#define rson id*2+1 //id的右子树编号
using namespace std;
int ans;
//id是每个所在区间的编号
//l和r是id所代表区间的左右节点
int tre[2000700];
int a,b,c,d,n,m,k;
int push(int id)
{
tre[id]=tre[lson]+tre[rson];//把子叶的值拿来更新父亲节点的值
return 0;
}
int build(int id,int l,int r) //树的初始化,必须的操作,虽然我也不知道为什么,好像是为了给每个点编号
{
if (l>r) return 0;//去除非法状态,以下每个子函数都要写
if (l==r)
{
tre[id]=0;
return 0;
}
int mid=(l+r)/2;
build(lson,l,mid);//递归左右子树
build(rson,mid+1,r);//注意是mid+1
push(id);
}
int add(int id,int l,int r,int pos,int num) //在编号为id的区间【l,r】中,在pos位置插入num
{
if(l>r) return 0;//判断非法状态
if (l==r && r==pos) //如果到了最后一层,更新值,记得return掉
{
tre[id]+=num;
return 0;
}
int mid=(l+r)/2;
if (pos<=mid)//如果pos在当前区间中点的左边,则在左子树中递归,反之在右子树中递归
{
add(lson,l,mid,pos,num);
}
if (pos>=mid+1)
{
add(rson,mid+1,r,pos,num);
}
push(id);//下一层递归完成后对本层进行更新
}
int query(int id,int l,int r,int L,int R)
{
if (l>r || L>R) return 0; //非法状态
if (l>=L && r<=R)
{
ans+=tre[id];
return 0;//一定记得return,都则id会大的飞起
}
int mid=(l+r)/2;
if (L<=mid) //如果所查询区间和【l,r】的左半边有重合,则递归求左半边,右半边同理
{
query(lson,l,mid,L,R);
}
if (mid+1<=R)
{
query(rson,mid+1,r,L,R);
}
return 0;
}
int main()
{
/******************
使用方法
1,初始化: build(1,1,maxx) maxx是所开数组的长度或者题目要求的长度
2,给节点加值 add(1,1,maxx,pos,num) pos是位置,num是数值
3,查询区间[L,R]的和 query(1,1,maxx,L,R)
******************/
build(1,1,1000);
int n,m,a,b;
cin>>n>>m;
for (int i=1;i<=n;i++)
{
scanf("%d%d",&a,&b);
add(1,1,m,a,b);
}
for (int i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
ans=0;
query(1,1,m,a,b);
cout<<ans<<endl;
}
}