LOJ 一本通提高篇4.1树状数组 例题+练习

复习时食用,会比较简略。

原理不讲,还不会的先下车。


目录

#130. 树状数组 1 :单点修改,区间查询—>板子不讲。

#10114. 「一本通 4.1 例 2」数星星 Stars

#10115. 「一本通 4.1 例 3」校门外的树

#10116. 「一本通 4.1 练习 1」清点人数—>板子不讲。

#10117. 「一本通 4.1 练习 2」简单题

#133. 二维树状数组 1:单点修改,区间查询


#10114. 「一本通 4.1 例 2」数星星 Stars

题目

题目大意

给定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<cstdio>
#include<cstring>
#include<algorithm>
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;
}

 

#10115. 「一本通 4.1 例 3」校门外的树

题目

题目大意

有两种操作:

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<cstdio>
#include<cstring>
#include<algorithm>
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;
}

 

#10117. 「一本通 4.1 练习 2」简单题

 

#133. 二维树状数组 1:单点修改,区间查询

题目

题目大意

给出一个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,且询问的子矩阵存在。 

  • 1 x y k:表示元素Ax,y自增k;
  • 2 a b c d:表示询问左上角为(a,b),右下角为(c,d)的子矩阵内所有数的和。

题目分析

求矩阵:sum(x2, y2)-sum(x2,y1-1)-sum(x1-1,y2)+sum(x1-1,y1-1)

这个不用说了都知道吧。不懂???画图去。

显然这是个二维树状数组。

你让我讲我也不会讲(来自蒟蒻的理直气壮)。

好吧。要看大橘,目光要长远。你需要把ta抽丝剥茧?让ta现出本质。

All in all:每一行是一个树状数组,每一列是一个树状数组。(仔细琢磨啊!!)

看完的把你画的图90度转看哈。

就这样。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
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;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值