树状数组
定点修改,区间查询
下标从1开始
动态求连续区间和
给定 n 个数组成的一个数列,规定有两种操作,一是修改某个元素,二是求子数列 [a,b] 的连续和。
输入格式
第一行包含两个整数 n 和 m,分别表示数的个数和操作次数。
第二行包含 n 个整数,表示完整数列。接下来 m 行,每行包含三个整数 k,a,b (k=0,表示求子数列[a,b]的和;k=1,表示第 a 个数加 b)。数列从 1 开始计数。
输出格式
输出若干行数字,表示 k=0 时,对应的子数列 [a,b] 的连续和。
数据范围
1≤n≤100000,1≤m≤100000,1≤a≤b≤n,
数据保证在任何时候,数列中所有元素之和均在 int 范围内。
输入样例:
10 5
1 2 3 4 5 6 7 8 9 10
1 1 5
0 1 3
0 4 8
1 7 5
0 4 8
输出样例:
11
30
35
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100010;
int n,m;
int a[N],tr[N];
int lowbit(int x)
{
return x&-x;
}
void add(int x,int v)
{
for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=v;
}
int query(int x)
{
int res=0;
for(int i=x;i;i-=lowbit(i)) res+=tr[i];
return res;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) add(i,a[i]);
while(m--)
{
int k,x,y;
scanf("%d%d%d",&k,&x,&y);
if(k==0) printf("%d\n",query(y)-query(x-1));
else add(x,y);
}
}
数星星
天空中有一些星星,这些星星都在不同的位置,每个星星有个坐标。如果一个星星的左下方(包含正左和正下)有 k颗星星,就说这颗星星是 k级的。
例如,上图中星星 5是 3级的(1,2,4在它左下),星星 2,4 是 1
级的。
例图中有 1 个 0 级,2个 1级,1个 2级,1个 3级的星星。
给定星星的位置,输出各级星星的数目。
换句话说,给定 N 个点,定义每个点的等级是在该点左下方(含正左、正下)的点的数目,试统计每个等级有多少个点。
输入格式
第一行一个整数 N,表示星星的数目;
接下来 N 行给出每颗星星的坐标,坐标用两个整数 x,y 表示;
不会有星星重叠。星星按 y 坐标增序给出,y 坐标相同的按 x 坐标增序给出。
输出格式
N 行,每行一个整数,分别是 0 级,1 级,2 级,……,N−1 级的星星的数目。
数据范围
1≤N≤15000,
0≤x,y≤32000
输入样例:
5
1 1
5 1
7 1
3 3
5 5
输出样例:
1
2
1
1
0
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N=32010;
int n;
int tr[N],level[N];
int lowbit(int x)
{
return x&-x;
}
int add(int x)
{
for(int i=x;i<N;i+=lowbit(i)) tr[i]++;
}
int sum(int x)
{
int res=0;
for(int i=x;i;i-=lowbit(i))
res+=tr[i];
return res;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
x++; //从1开始
level[sum(x)]++;
add(x);
}
for(int i=0;i<n;i++) printf("%d\n",level[i]);
}
线段树
操作一:单点修改 o(logn)
操作二:区间查询 o(logn)
操作
pushup():用子节点信息更新当前节点信息
build():在一段区间上初始化线段树
modify():修改
query():查询
动态求连续区间和
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N=100010;
int n,m;
int w[N];
struct node{
int l,r;
int sum;
}tr[N*4];
void pushup(int u)
{
tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;//左右儿子的和
}
void build(int u,int l,int r)
{
if(l==r) tr[u]={l,r,w[r]};
else
{
tr[u]={l,r};
int mid=l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
pushup(u);
}
}
int query(int u,int l,int r)
{
if(tr[u].l>=l&&tr[u].r<=r) return tr[u].sum;
int mid=tr[u].l+tr[u].r>>1;
int sum=0;
if(l<=mid) sum=query(u<<1,l,r);
if(r>mid) sum+=query(u<<1|1,l,r);
return sum;
}
void modify(int u,int x,int v )
{
if(tr[u].l==tr[u].r) tr[u].sum+=v;
else {
int mid=tr[u].l+tr[u].r>>1;
if(x<=mid) modify(u<<1,x,v);
else modify(u<<1|1,x,v);
pushup(u);
}
}
int main()
{scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
build(1,1,n);
int k,a,b;
while(m--)
{
scanf("%d%d%d",&k,&a,&b);
if(k==0) printf("%d\n",query(1,a,b)); //根结点编号
else modify(1,a,b); //根节点编号,插入的位置,插入的值
}
}