2017西安交大ACM小学期数据结构 [树状数组,极大值]

Problem D

发布时间: 2017年6月28日 10:51   最后更新: 2017年6月28日 16:38   时间限制: 1000ms   内存限制: 32M

给定一个长度为 n 的序列 a1 a2 , ...,  an

k 满足 2kn1 ak>ak1 ak>ak+1 时, 将元素 k 称为极大值点,

给出 q 个操作, 操作分为两种

对于形如 1   x   y 的操作, 将 ax 修改为 y , 满足 1xn 1y109

对于形如 2   x   y 的操作, 输出区间 [x,y] 内有多少个"极大值点", 满足 1xyn

9×104n105 9×104q105 1ai109

第一行两个整数 n q , 意义如上所述。
第二行 n 个整数, 表示序列 a
接下来 q 行, 每行第一个数为 opt , 之后紧跟两个数, 意义如上所述。

对于每个操作 2 , 输出答案, 一行一个。

  复制
8 3
3 1 4 1 5 9 2 6
2 1 8
1 3 1
2 1 8
2
1
我们可以直接创建一个树状数组,如果某个元素x是极大值,那么我们就往蜀树状数组相应的位置写上1,这样的话,想要统计区间最大值的个数,只需要

统计树状数组的区间和就可以了。

而在维护的时候(修改a[x] 为y)要小心的考虑

这里举一个例子,要将a[x]改为y的情况

(1)如果修改前a[x]是极大值,修改后a[x]非极大值,那么add(x,-1)

(2)如果修改前a[x]非极大值,修改后a[x]为极大值,那add(x,-1)

(3).。。注意a[x]改成y不光影响x出的值,x-1,x+1处都有可能被影响

。。。要注意

代码:

#include <iostream>
#include <cstdio>
using namespace std;
const int MAX = 1e5+7;
int n,q;
int a[MAX];
int b[MAX];
inline int lowbit(int x){
	return x & (-x);
}
int getsum(int pos){
	int res = 0;
	while(pos){
		res += b[pos];
		pos -= lowbit(pos);
	}
	return res;
}
void add(int pos,int val){
	while(pos <= n){
		b[pos] += val;
		pos += lowbit(pos);
	}
}
inline bool check(int pos){
	return a[pos] > a[pos+1] && a[pos] > a[pos-1];
}

int main(){
	scanf("%d%d",&n,&q);
	for(int i = 1;i <= n;i++){
		scanf("%d",&a[i]);
	}
	for(int i = 2;i < n;i++){
		if(check(i)){
			add(i,1);
		}
	}
	while(q--){
		int opt;
		scanf("%d",&opt);
		if(opt == 1){
			int x,y;
			scanf("%d%d",&x,&y);
			if(x == 1){
				if(!check(2) && (a[2] > y && a[2] > a[3])){
					add(2,1);
				}
				if(check(2) && !(a[2] > y && a[2] > a[3])){
					add(2,-1);
				}
			}
			else if(x == n){
				if(!check(n-1) && (a[n-1] > a[n-2] && a[n-1] > y)){
					add(n-1,1);
				}
				if(check(n-1) && !(a[n-1] > a[n-2] && a[n-1] > y)){
					add(n-1,-1);
				}
			}
			else{
				if(!check(x) && (y > a[x-1] && y > a[x+1]) ){
					add(x,1);
				}
				if(check(x) && !(y > a[x-1] && y > a[x+1]) ){
					add(x,-1);
				}
				if(x >= 3 && !check(x-1) && (a[x-1] > a[x-2] && a[x-1] > y)){
					add(x-1,1);
				}
				if(x >= 3 && check(x-1) && !(a[x-1] > a[x-2] && a[x-1] > y)){
					add(x-1,-1);
				}
				if(x <= n-2 && !check(x+1) && (a[x+1] > a[x+2] && a[x+1] > y)){
					add(x+1,1);
				}
				if(x <= n-2 && check(x+1) && !(a[x+1] > a[x+2] && a[x+1] > y)){
					add(x+1,-1);
				}
			}
			a[x] = y;
		}
		else{
			int x,y ;scanf("%d%d",&x,&y);
			printf("%d\n",getsum(y) - getsum(x-1));
		}
	}
	return 0;
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值