复习时食用,会比较简略。
原理不讲,还不会的先下车。
目录
#130. 树状数组 1 :单点修改,区间查询—>板子不讲。
#10114. 「一本通 4.1 例 2」数星星 Stars
#10115. 「一本通 4.1 例 3」校门外的树
#10116. 「一本通 4.1 练习 1」清点人数—>板子不讲。
#10117. 「一本通 4.1 练习 2」简单题
#133. 二维树状数组 1:单点修改,区间查询
题目
给定n个点。
定义每个点的等级是在该点左下方(含正左、正下)的点的数目。
试统计每个等级有多少个点。
坐标用两个整数x,y表示,不会有星星重叠。
星星按y坐标增序给出, 坐标相同的按x坐标增序给出。
对于全部数据,1<=N<=1.5*10^4,0<=x,y<=3.2*10^4。
我都加粗了的东西你一定要看!这道题好像跟板子没什么区别。
因为已经按y坐标增序给出了,所以可以一边输入一边做。
(在ta前面输入的在ta的下面,在ta后面输入的y坐标比ta大所以对ta没什么影响)
然后就看小于等于ta的x坐标(即在ta的左边或下面)就好啦。
噢还有一个big keng:lowbit(0)=0!!!麻烦手动右移一位。
以上。
#include
#include
#include
using namespace std;
int n,tr[64010],ans[15010];
int lowbit(int x) { return x&-x; }
void add(int x)
{
while(x<=32001)
{
tr[x]++;
x+=lowbit(x);
}
}
int sum(int x)
{
int s=0;
while(x!=0)
{
s+=tr[x];
x-=lowbit(x);
}
return s;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x,y; scanf("%d%d",&x,&y);
x++; add(x); ans[sum(x)-1]++;//不包括ta自己
//lowbit(0)=0树状数组的坐标里没0
//所以都向右移一位ba
}
for(int i=0;i<=n-1;i++) printf("%d\n",ans[i]);
return 0;
}
题目
有两种操作:
k=1,读入l,r表示在l到r之间种上一种树,每次操作种的树的种类都不同;
k=2,读入l,r表示询问l到r之间有多少种树。
对于20%的数据,1<=n,m<=100;
对于60%的数据,1<=n<=10^3,1<=m<=5*10^4;
对于100%的数据,1<=n,m<=5*10^4,保证l,r>0。
核心(敲黑板!!!):answer=一共有的树的种类-前面有我没有的种类-后面有我没有的种类。
没了?没了。
#include
#include
#include
using namespace std;
int n,m,jia=0;//jia即为一共有的树的种类
int trl[100010],trr[100010];
int lowbit(int x) { return x&-x; }
void add(int x,int a[])
{
while(x<=n)
{
a[x]++;
x+=lowbit(x);
}
}
int sum(int x,int a[])
{
int s=0;
while(x)
{
s+=a[x];
x-=lowbit(x);
}
return s;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int k,x,y; scanf("%d%d%d",&k,&x,&y);
if(k==1) jia++,add(n-x+1,trl),add(y,trr);
else printf("%d\n",jia-sum(x-1,trr)-sum(n-y,trl));
//核心核心!answer=树的种类-前面有我没有的-后面有我没有的
//画图画图!!!
}
return 0;
}
题目
给出一个n*m的零矩阵,要完成如下操作:
对于10%的数据,n=1;
对于另10%的数据,m=1;
对于全部数据,1<=n,m<=2^12,1<=x,a,c<=n,1<=y,b,d<=m,|k|<=10^5。
保证操作数目不超过3*10^5,且询问的子矩阵存在。
求矩阵:sum(x2, y2)-sum(x2,y1-1)-sum(x1-1,y2)+sum(x1-1,y1-1)。
这个不用说了都知道吧。不懂???画图去。
显然这是个二维树状数组。
你让我讲我也不会讲(来自蒟蒻的理直气壮)。
好吧。要看大橘,目光要长远。你需要把ta抽丝剥茧?让ta现出本质。
All in all:每一行是一个树状数组,每一列是一个树状数组。(仔细琢磨啊!!)
看完行的把你画的图90度转看列哈。
就这样。
#include
#include
#include
using namespace std;
int n,m;
long long tr[8200][8200];
int lowbit(int x) { return x&-x; }
void add(int x,int y,int k)
{
while(x<=n)
{
int yy=y;
while(yy<=m)//一维变二维!
{
tr[x][yy]+=k;
yy+=lowbit(yy);
}
x+=lowbit(x);
}
}
long long sum(int x,int y)
{
long long s=0;
while(x!=0)
{
int yy=y;
while(yy!=0)
{
s+=tr[x][yy];
yy-=lowbit(yy);
}
x-=lowbit(x);
}
return s;
}
int main()
{
scanf("%d%d",&n,&m); int t;
while(scanf("%d",&t)!=EOF)
{
if(t==1)
{
int x,y,k;
scanf("%d%d%d",&x,&y,&k);
add(x,y,k);
}
else
{
int a,b,c,d; scanf("%d%d%d%d",&a,&b,&c,&d);
long long aa,bb=0,cc=0,dd=0;
aa=sum(c,d);
if(b-1) bb=sum(c,b-1);
if(a-1) cc=sum(a-1,d);
if((a-1)&&(b-1)) dd=sum(a-1,b-1);
printf("%lld\n",aa-bb-cc+dd);
//求矩阵
}
}
return 0;
}