CODEVS(WIKIOI) 2018 反病毒软件(线段树)

本文介绍了一种使用线段树解决城市值查询问题的方法,包括点修改和区间查询最大值与次大值之差。通过维护节点的最大值与次大值及其对应的城市编号,确保了查询结果的准确性。

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

n个城市,点修改,区间询问最大值与第二大值之差,很明显的线段树。此题有点水。

求最大值与第二大值之差,就维护最大值与第二大的值,每次修改时更新值。

设最大值为fir,第二大为sec,如果x<sec则不修改,如果x>fir,把fir变成x,sec变成fir,如果fir<x<sec,sec=x;

这样子看上去好像对了但实际上会WA,为什么呢?这样子做的话会出现这种情况:

1-5: fir:5(3号城市) sec:2(1号城市)

如果再对于3号城市加上3,那么因为5+3=8>5(fir) sec=5,fir=8(都是3号城市,但sec是历史值),就不是第一、二大的城市之差。

所以还应该记录第一、二大值所在城市,如果x>fir,并且城市相同,直接fir=x。

查询时全局设变量maxn,secn,记录当前查询到的第一、二大的值,并且每次查询前初始化为0。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <queue>
#include <climits>
#include <ctime>
#include <stack>
#include <iostream>
using namespace std;
int maxn=0,secn=0;
class node{
public:
	int l,r,fir,sec,fc,sc;
	node *lt,*rt;
	node(){
		l=0,r=0,fir=0,sec=0,fc=0,sc=0;
		lt=NULL,rt=NULL;
	}
	void build(int ll,int rr)
	{
		l=ll,r=rr;
		if(rr-ll>1){
			int mid=(l+r)>>1;
			lt=new node;
			lt->build(ll,mid);
			rt=new node;
			rt->build(mid,rr);
		}
	}
	int insert(int num,int inc)
	{
		if(num==l &&num+1==r){fir+=inc;return fir;}
		int mid=(l+r)>>1,tmp;
		if(num<mid) tmp=lt->insert(num,inc);
		if(num>=mid) tmp=rt->insert(num,inc);
		if(tmp==0 || tmp<=sec) return 0;
		if(tmp>fir){
			if(fc==num) fir=tmp;
			else{
				sc=fc,sec=fir;
				fc=num,fir=tmp;
			}
		}
		else sec=tmp,sc=num;
		return tmp;
	}
	void que(int ll,int rr){
		if(ll==l && r==rr){
			if(sec>maxn) secn=maxn,maxn=sec;
			else if(sec>secn) secn=sec;
			if(fir>maxn) secn=maxn,maxn=fir;
			else if(fir>secn) secn=fir;
			return;
		}
		int mid=(l+r)>>1;
		if(rr<=mid) lt->que(ll,rr);
		else if(ll>=mid) rt->que(ll,rr);
		else lt->que(ll,mid),rt->que(mid,rr); 
	}
}*tree;
int n,q;
int main()
{
	int x,y,c;
	scanf("%d%d",&n,&q);
	tree=new node;
	tree->build(1,n+1);
	for(int i=1;i<=q;i++){
		scanf("%d%d%d",&c,&x,&y);
		if(c==1) tree->insert(x,y);
		else maxn=0,secn=0,tree->que(x,y+1),printf("%d\n",maxn-secn);
	}
	system("pause");
	return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值