洛谷P1020 导弹拦截 树状数组区间求最值

本文介绍了一种基于树状数组的高效算法,用于解决导弹拦截问题。通过计算最长不升子序列和最长下降子序列来确定最多能拦截的导弹数量及所需系统的套数。采用O(log n)的时间复杂度实现,利用树状数组进行区间查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

思路:

  1. 求最多能拦截多少导弹是求最长不升子序列
  2. 求配备多少套这种系统是求最长下降子序列
  3. 题目要求做法为O(log⁡n)O(\log{n})O(logn)
  4. 题目的本质是最值的区间查询

举例:
序列:389 207 155 300 299 170 158 65
最值(向上):1 2 3 2 3 4 5 6
最值(向下):1 1 1 2 2 2 2 1
我们只需要贪心的选取之前的最值即可

代码:

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e5+500;

int tot,a[maxn];//原数组
int t[maxn],mx;	//树状数组与上边界

int query1(int x){	// max(x,...,mx)
	int res = 0;
	for(int i=x;i<=mx;i+=i&-i)
		res = max(res,t[i]);
	return res;
}

void update1(int x,int val){
	for(int i=x;i;i-=i&-i)
		t[i] = max(t[i],val);
}

int query2(int x){
	int res = 0;
	for(int i=x;i;i-=i&-i)
		res = max(res,t[i]);
	return res;
}

void update2(int x,int val){
	for(int i=x;i<=mx;i+=i&-i)
		t[i] = max(t[i],val);
}

void solve1(){		//最长不升子序列
	int res = 0;
	for(int i=0;i<tot;i++){
		int now = query1(a[i])+1;
		res = max(res,now);
		update1(a[i],now);
		//不是update1(a[i]+1,now),因为自己的值也能贪心的选取
	}
	printf("%d\n",res);
}

void solve2(){		//最长下降子序列
	memset(t,0,sizeof(t));
	int res = 0;
	for(int i=0;i<tot;i++){
		int now = query2(a[i])+1;
		res = max(res,now);
		update2(a[i]+1,now);
	}
	printf("%d\n",res);
}


int main(){
	while(scanf("%d",&a[tot])!=EOF)
		mx = max(mx,a[tot++]);
	solve1();	//求最长不升子序列
	solve2();	//求最长下降子序列
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值