HDU1754 I Hate It (树状数组 | 线段树)

11 篇文章 0 订阅
7 篇文章 0 订阅

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1754


解法一:树状数组:

首先要注意下query()函数里的操作和update()函数里的操作。

先解释下update()函数里的操作,令原数组a[i] = num,即每次都使得a[i]中保留第i个学生最新的成绩。这个操作在query()函数里将会有较大的用处。

再来说下关于query()的操作,首先当l == r的时候,当前区间的最大值肯定就是a[l];当l != r时,我们要求[l,r]区间里的最大值,又可以知道,tree[]数组中保留的是前缀值,所以单纯的按照以前的思路用r - (l-1)求区间最大值肯定不行。我们都了解树状数组的存储方式,当i=4时,tree[i]存储的是前4个的前缀值,当i=6时,tree[i]中存储的是5和6之间的最大值,假设题目让求区间[3,8]的最大值,肯定不能比较tree[8],因为tree[8]中存储的是 前8个数的最大值,该值可能不在当前要查询的区间内。退而求其次,我们可以比较a[8]的值,因为a[8]中存储的是第8个人的最大值。但是我们可以直接求tree[6],因为tree[6]中存储的是第5个和第6个的最大值。但是当我们遇到r == 8的时候该怎么办呢?  假设当r==8时,则 r - (r & -r) = 0,肯定小于左区间l的值,也就是说如果当前 i - (i & -i) >= l,则该点的tree[]值所管的点都在该[l,r]区间内,否则 比较a[i],然后 i--即可。


AC代码如下:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <climits>
#include <cstring>
#include <string>
#include <set>
#include <bitset>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <cassert>
#include <ctime>
#define rep(i,m,n) for(i=m;i<=(int)n;i++)
#define mod 100000007
#define inf 0x3f3f3f3f
#define vi vector<int>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define ll long long
#define pi acos(-1.0)
#define pii pair<int,int>
#define sys system("pause")
#define ls rt<<1
#define rs rt<<1|1
#define all(x) x.begin(),x.end()
const int maxn=2e5+10;
const int N=5e2+10;
using namespace std;
ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
ll qmul(ll p,ll q,ll mo){ll f=0;while(q){if(q&1)f=(f+p)%mo;p=(p+p)%mo;q>>=1;}return f;}
ll qpow(ll p,ll q,ll mo){ll f=1;while(q){if(q&1)f=qmul(f,p,mo)%mo;p=qmul(p,p,mo)%mo;q>>=1;}return f;}

int n,m,tree[maxn],a[maxn]; 

int lowbit(int k){
	return k & -k;
}

void update(int k, int num){
	a[k] = num;
	while(k <= n){
		tree[k] = max(tree[k],num);
		k += lowbit(k);
	}
}

int query(int l, int r){
	int ans = a[r];
	while(l != r){
		for(r -= 1; r - lowbit(r) >= l; r -= lowbit(r)){
			ans = max(ans,tree[r]);
		}
		ans = max(ans,a[r]);
	}
	return ans;
}

int main(){
	while(~scanf("%d%d",&n,&m)){
		memset(tree,0,sizeof(tree));
		for(int i = 1; i <= n; i ++){
			scanf("%d",&a[i]);
			update(i,a[i]);
		}
		char str[10];
		while(m --){
			scanf("%s",str);
			int i,j;
			scanf("%d%d",&i,&j);
			if(str[0] == 'Q'){
				int ans = query(i,j);
				printf("%d\n",ans);
			}
			else{
				update(i,j);
			}
		}
	}
	return 0;
} 




解法二:线段树


在一个总的区间的最大值mxx = max(左区间最大值,右区间最大值);


AC代码如下:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define inf 0x3f3f3f3f
#define ll long long
#define ls rt << 1
#define rs rt << 1 | 1
#define pi acos(-1.0)
using namespace std;

const int maxn = 2e5 + 5;
int n,m,sum[maxn<<2],add[maxn<<2],a[maxn];

void PushUp(int rt){
	sum[rt] = max(sum[ls],sum[rs]);
}

void Build(int l, int r, int rt){
	if(l == r){
		sum[rt] = a[l];	return;
	}
	int m = (l + r) >> 1;
	Build(l,m,ls);	Build(m+1,r,rs);
	PushUp(rt);
}

void Update(int L, int C, int l, int r, int rt){
	if(l == r){
		sum[rt] = C; return ;
	}
	int m = (l + r) >> 1;
	if(L <= m) Update(L,C,l,m,ls);
	else Update(L,C,m+1,r,rs);
	PushUp(rt);
}

int Query(int L, int R, int l, int r, int rt){
	if(L <= l && r <= R) return sum[rt];
	
	int m = (l + r) >> 1;
	int ans = 0;
	if(L <= m) ans = max(ans,Query(L,R,l,m,ls));
	if(R > m) ans = max(ans,Query(L,R,m+1,r,rs));
	return ans;
}

int main(){
	while(~scanf("%d%d",&n,&m)){
		for(int i = 1; i <= n; i ++)
			scanf("%d",&a[i]);
		memset(sum,0,sizeof(sum));
		memset(add,0,sizeof(add));
		Build(1,n,1);
		char str[10];
		while(m --){
			scanf("%s",str);
			int b,c;
			if(str[0] == 'Q'){
				scanf("%d%d",&b,&c);
				int ans = Query(b,c,1,n,1);
				printf("%d\n",ans);
			}
			else{
				scanf("%d%d",&b,&c);
				Update(b,c,1,n,1);
			}
		}
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值