【题目整理】树状数组

hdu1116 敌兵布阵(单点更新+区间查询)

【题意】

每组数据第一行一个正整数N(N<=50000),表示敌人有N个工兵营地,接下来有N个正整数,第i个正整数ai代表第i个工兵营地里开始时有ai个人(1<=ai<=50)。
接下来每行有一条命令,命令有4种形式:
(1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30)
(2)Sub i j ,i和j为正整数,表示第i个营地减少j个人(j不超过30);
(3)Query i j ,i和j为正整数,i<=j,表示询问第i到第j个营地的总人数;
(4)End 表示结束,这条命令在每组数据最后出现;


【解题思路】

算是一道很模板的模板题了,但是为了熟悉一下树状数组我觉得挑一道模板题里入门还是不错滴。

【代码】

#include<bits/stdc++.h>
using namespace std;
int n,c[50005];
int lowbit(int x)
{
	return x&(-x);
}
void add(int x,int v)
{
	while(x<=n){
		c[x]+=v;
		x+=lowbit(x);
	}
}
int query(int x)
{
	int sum=0;
	while(x>0){
		sum+=c[x];
		x-=lowbit(x);
	}
	return sum;
}
int main()
{
	int T,k=1;
	scanf("%d",&T);
	while(T--){
		memset(c,0,sizeof(c));
		char s[10];
		scanf("%d",&n);
		for(int i=1;i<=n;i++){
			int t;
			scanf("%d",&t);
			add(i,t);
		}
		printf("Case %d:\n",k++);
		while(~scanf("%s",s) && s[0]!='E'){
			int x,y;
			scanf("%d%d",&x,&y);
			if(s[0]=='A'){
				add(x,y);
			}
			else if(s[0]=='S'){
				add(x,-y);
			}
			else if(s[0]=='Q'){
				printf("%d\n",query(y)-query(x-1));
			}
		}
	}
	return 0;
}

zcmu1156 新年彩灯Ⅰ(区间更新+单点查询)

【题意】

YY准备挂一排彩灯,已知彩灯刚挂完的彩灯共有N盏(编号为1,2,3,……),并且都是灭的。彩灯的闪烁由一段程序控制。每一秒钟程序会生成两个正整数a和b(1<=a,b<=N),然后将编号为a和b之间的所有灯的状态改变一次。

然后是M行数据,包括以下两种形式:

         1 a b 表示灯a和灯b之间的灯(含灯a和灯b)变换一次状态。

         0 x y 表示YY想知道此刻灯x到灯y(包含灯x和灯y)的状态。

【解题思路】

每对灯进行一次操作就将该区间内的灯+1,稍微模拟一下就能发现,当灯为偶数时,其实就是熄灭的状态,奇数则是亮着的。

然后这里要注意一下a,b的位置是不确定的,当b<a的时候记得swap。

【代码】

#include<bits/stdc++.h>
using namespace std;
int n,c[1000005];
int lowbit(int x)
{
	return x&(-x);
}
void update(int x,int v)
{
	while(x<=n){
		c[x]+=v;
		x+=lowbit(x);
	}
}
int query(int x)
{
	int sum=0;
	while(x){
		sum+=c[x];
		x-=lowbit(x);
	}
	return sum;
}
void range_update(int x,int y,int t)
{
	add(x,t);
	add(y+1,-t);
}
int main()
{
	int m;
	while(~scanf("%d%d",&n,&m)){
		memset(c,0,sizeof(c));
		int p,a,b;
		while(m--){
			scanf("%d%d%d",&p,&a,&b);
			if(b<a)swap(a,b);
			if(p==1)update(a,b,1);
			else{
				for(int i=a;i<=b;i++){
					int t=query(i);
					if(t%2)printf("1");
					else printf("0");
				}
				printf("\n");
			}
		}
	}
	return 0;
}

洛谷3368 【模板】树状数组2(区间查询+单点更新)

【题意】

如题,已知一个数列,你需要进行下面两种操作:

1.将某区间每一个数数加上x

2.求出某一个数的和

【解题思路】

就是套模板啦~目前树状数组只会套模板的我qaq因为是区间查询,记得将c数组变成差分数组

【代码】

#include<bits/stdc++.h>
using namespace std;
int n,c[500005];
int lowbit(int x)
{
	return x&(-x);
}
void update(int x,int v)
{
	while(x<=n){
		c[x]+=v;
		x+=lowbit(x);
	}
}
int ask(int x)
{
	int sum=0;
	while(x>0){
		sum+=c[x];
		x-=lowbit(x);
	}
	return sum;
}
void range_update(int a,int b,int v)
{
	update(a,v);
	update(b+1,-v);
}
int main()
{
	int m,x,t=0;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&x);
		update(i,x-t);
		t=x;
	}
	while(m--){
		int p;
		scanf("%d",&p);
		if(p==1){
			int a,b,c;
			scanf("%d%d%d",&a,&b,&c);
			range_update(a,b,c);
		}
		else if(p==2){
			int c;
			scanf("%d",&x);
			printf("%d\n",ask(x));
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39826163/article/details/81281739