【学习笔记】用线段树维护区间计数问题

news2024/9/21 16:46:30

前言

简单的区间计数问题可能直接推式子就行了。
但有些问题必须要数据结构维护。线段树就是一个比较好的处理区间的数据结构。

Gym102222L

在这里插入图片描述

在这里插入图片描述

思路

满足条件的区间特征: max ⁡ { a i } − min ⁡ { a i } + 1 − c n t = 0 \max\{a_i\}-\min\{a_i\}+1-cnt=0 max{ai}min{ai}+1cnt=0,其中 c n t cnt cnt 代表区间内不同数字的个数。
考虑固定右端点,统计有多少个合法的左端点。
我们可以用线段树维护 m i n v = min ⁡ { max ⁡ { a i } − min ⁡ { a i } − c n t } minv=\min\{\max\{a_i\}-\min\{a_i\}-cnt\} minv=min{max{ai}min{ai}cnt} n u m = 有多少个区间左端点可以取到 m i n v num=有多少个区间左端点可以取到 minv num=有多少个区间左端点可以取到minv,答案就是 m i n v = − 1 minv=-1 minv=1 时的 n u m num num
max ⁡ { a i } \max\{a_i\} max{ai} min ⁡ { a i } \min\{a_i\} min{ai} 可以用两个单调栈维护。

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+7,inf=1e18;
struct seg
{
	int minv,tag,cnt;
	seg()
	{
		minv=tag=cnt=0;
	}
};
vector<seg> tr;
void update(int u)
{
	tr[u].minv=min(tr[u<<1].minv,tr[u<<1|1].minv);
	if(tr[u<<1].minv==tr[u<<1|1].minv)
	{
		tr[u].cnt=tr[u<<1].cnt+tr[u<<1|1].cnt;
	}
	else if(tr[u].minv==tr[u<<1].minv)
	{
		tr[u].cnt=tr[u<<1].cnt;
	}
	else if(tr[u].minv==tr[u<<1|1].minv)
	{
		tr[u].cnt=tr[u<<1|1].cnt;
	}
	else
	{
		assert(false);
	}
}
void pushdown(int u)
{
	if(tr[u].tag)
	{
		tr[u<<1].minv+=tr[u].tag; tr[u<<1|1].minv+=tr[u].tag;
		tr[u<<1].tag+=tr[u].tag; tr[u<<1|1].tag+=tr[u].tag;
		tr[u].tag=0;
	}
}
void build(int u,int st,int ed)
{
	if(st==ed)
	{
		tr[u].cnt=1;
		return;
	}
	int mid=st+ed>>1;
	build(u<<1,st,mid);
	build(u<<1|1,mid+1,ed);
	update(u);
}
void modify(int u,int st,int ed,int l,int r,int x)
{
	if(l<=st&&ed<=r)
	{
		tr[u].minv+=x;
		tr[u].tag+=x;
		return;
	}
	pushdown(u);
	int mid=st+ed>>1;
	if(mid>=l)
		modify(u<<1,st,mid,l,r,x);
	if(mid<r)
		modify(u<<1|1,mid+1,ed,l,r,x);
	update(u);
}
int query(int u,int st,int ed,int l,int r)
{
	if(l<=st&&ed<=r)
	{
		return tr[u].minv==-1?tr[u].cnt:0;
	}
	pushdown(u);
	int mid=st+ed>>1;
	int res=0;
	if(mid>=l)
		res=query(u<<1,st,mid,l,r);
	if(mid<r)
		res+=query(u<<1|1,mid+1,ed,l,r);
	return res;
}
int O_o()
{
	int n;
	cin>>n;
	tr.assign(n+1<<2,seg());
	vector<int> a(n+1),ls(n+1);
	map<int,int> mp;
	for(int i=1; i<=n; i++)
	{
		cin>>a[i];
		ls[i]=mp[a[i]];
		mp[a[i]]=i;
	}
	build(1,1,n);
	stack<array<int,2>> sx,sy;// decrease, increase
	int ans=0;
	for(int i=1; i<=n; i++)
	{
		int x=a[i];
		while(sx.size()&&x>sx.top()[0])
		{
			auto [v,id]=sx.top(); sx.pop();
			modify(1,1,n,sx.size()?(sx.top()[1]+1):1,id,x-v);
		}
		sx.push({x,i});
		while(sy.size()&&x<sy.top()[0])
		{
			auto [v,id]=sy.top(); sy.pop();
			modify(1,1,n,sy.size()?(sy.top()[1]+1):1,id,v-x);
		}
		sy.push({x,i});
		modify(1,1,n,ls[i]+1,i,-1);
		ans+=query(1,1,n,1,i);
	}
	return ans;
}
signed main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cout<<fixed<<setprecision(12);
	int T=1;
	cin>>T;
	for(int i=1; i<=T; i++)
	{
		cout<<"Case #"<<i<<": "<<O_o()<<"\n";
	}
}

2024牛客暑期多校训练营7 D

在这里插入图片描述
在这里插入图片描述

思路

首先预处理每个点要往后走到哪才会出现 k k k 次和 k + 1 k+1 k+1
具体的,令 L i L_i Li 为从点 i i i 往后走,出现 k k k a i a_i ai 的最近位置;令 R i R_i Ri 为从点 i i i 往后走,出现 k k k a i a_i ai 的最远位置。
考虑倒着枚举左端点,对于每个左端点考虑有多少个右端点是合法的。

我们定义点 i i i 的合法区间为 [ L i , R i ] ∪ [ 1 , i − 1 ] [L_i,R_i]∪[1,i-1] [Li,Ri][1,i1] [ L i , R i ] [L_i,R_i] [Li,Ri] a i a_i ai 出现了 k k k 次, [ 1 , i − 1 ] [1,i-1] [1,i1] 不在 i i i 的管辖范围内),那么对于 i i i 为左端点的答案就是 [ i , n ] [i,n] [i,n] 中所有不同的数最前面的合法区间的交集。

也就是我们要维护一棵线段树,支持区间加、区间减、求区间最大值和最大值个数。这样做其实有些麻烦。
不难想到,合法区间的交集 = 不合法区间的并集的反集,求区间的并就完全可以像扫描线那样做。

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+7,inf=1e18;
struct seg
{
	int val,len;
	seg()
	{
		val=len=0;
	}
};
vector<seg> tr;
int n;
void update(int u,int st,int ed)
{
	if(tr[u].val>0)
	{
		tr[u].len=ed-st+1;
	}
	else
	{
		if(st==ed)
		{
			tr[u].len=0;
			return;
		}
		tr[u].len=tr[u<<1].len+tr[u<<1|1].len;
	}
}
void add(int u,int st,int ed,int l,int r,int x)
{
	if(l>r||l>n||r>n) return;
	
	if(l<=st&&ed<=r)
	{
		tr[u].val+=x;
		update(u,st,ed);
		return;
	}
//	pushdown(u);
	int mid=st+ed>>1;
	if(mid>=l)
		add(u<<1,st,mid,l,r,x);
	if(mid<r)
		add(u<<1|1,mid+1,ed,l,r,x);
	update(u,st,ed);
}
int query(int u,int st,int ed,int l,int r)
{
	if(l>r||l>n||r>n) return 0;
	
	if(l<=st&&ed<=r)
	{
		return tr[u].len;
	}
	int mid=st+ed>>1;
	int res=0;
	if(mid>=l)
		res=query(u<<1,st,mid,l,r);
	if(mid<r)
		res+=query(u<<1|1,mid+1,ed,l,r);
	return res;
}
void O_o()
{
	int k;
	cin>>n>>k;
	map<int,vector<int>> mp;
	vector<int> a(n+1);
	for(int i=1; i<=n; i++)
	{
		cin>>a[i];
		mp[a[i]].push_back(i);
	}
	tr.assign((n<<2)+1,seg());
	vector<array<int,2>> pos(n+1);
	vector<int> p,nxt(n+1);
	p.push_back(-1);
	for(auto [v,t]:mp)
	{
		p.push_back(v);
		int m=t.size();
		for(int i=0; i<m; i++)
		{
			int l,r;
			if(i+k-1>=m)
			{
				l=n+1;
			}
			else 
				l=t[i+k-1];
			if(i+k>=m)
			{
				r=n+1;
			}
			else 
				r=t[i+k];
			pos[t[i]]={l,r};
			if(i==m-1)
				nxt[t[i]]=n+1;
			else nxt[t[i]]=t[i+1];
		}
	}
	int ans=0;
	for(int i=n; i>=1; i--)
	{
		if(nxt[i]!=n+1)
		{
			auto [l,r]=pos[nxt[i]];
			add(1,1,n,nxt[i],l-1,-1);
			add(1,1,n,r,n,-1);
		}
		auto [l,r]=pos[i];
		add(1,1,n,i,l-1,1);
		add(1,1,n,r,n,1);
		int t=query(1,1,n,i,n);
		ans+=(n-i+1)-t;
	}
	cout<<ans<<"\n";
}
signed main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cout<<fixed<<setprecision(12);
	int T=1;
	cin>>T;
	while(T--)
	{
		O_o();
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1995318.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uniapp离线打包热更新失败-AndroidStudio离线打包apk后无法下载打开-热更新失败-plus.runtime.install失败

效果图 仅安卓 前言 1.plus.runtime.install一直fail(20240808), uni.openDocument可以打开本地apk文件 2.权限问题需小心 跑通前提 1.先确定apk地址有效&#xff0c;浏览器中手动下载可安装 2.确保已添加离线打包AndroidStudio的“android.permission.INSTALL_PACKAGES”权…

初识自然语言处理NLP

文章目录 1、简介2、自然语言处理的发展简史3、语言学理论句法学&#xff08;Syntax&#xff09;语义学&#xff08;Semantics&#xff09;语用学&#xff08;Pragmatics&#xff09;形态学&#xff08;Morphology&#xff09; 4、统计与机器学习方法n-gram 模型隐马尔可夫模型…

JNPF快速开发平台赋能数字办公方式转变

随着信息技术的飞速发展&#xff0c;数字化转型已成为各行各业提升效率、优化流程的重要手段。JNPF快速开发平台正是在这样的背景下应运而生&#xff0c;它通过简化开发流程&#xff0c;使得非技术人员也能参与到应用的构建中来&#xff0c;从而加速了数字办公方式的转变。 数字…

解决r2dbc连mysql时timestamp字段的时区问题

现象&#xff1a; 在两个mysql库用相同SQL都建了某表&#xff0c;都有created_at字段&#xff1a; created_at timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, 。但是在往此表insert记录时&#xff0c;B库的created_at字段比当前时间慢了8个小时&#xff0c;而A…

MySQL学习(19):锁

1.什么是锁 锁是计算机协调多个进程或线程并发访问某一资源的机制。 在数据库中&#xff0c;数据是供许多用户共享的资源&#xff0c;数据库必须保证数据并发访问的一致性、有效性&#xff0c;这就要靠锁来协调实现。 MySOL中的锁&#xff0c;分为以下三类&#xff1a; &am…

深度学习基础 - 向量投影

深度学习基础 - 向量投影 flyfish 给定两个向量 a \mathbf{a} a 和 b \mathbf{b} b&#xff0c;我们想要计算 a \mathbf{a} a 在 b \mathbf{b} b 上的投影。 点乘 (Dot Product) 点乘是一个标量&#xff0c;表示两个向量在相同方向上的程度。公式为&#xff1a; a ⋅ b …

行为验证码热门行业解决方案

行为式验证码是一种较为流行的验证码。从字面来理解&#xff0c;就是通过用户的操作行为来完成验证&#xff0c;而无需去读懂扭曲的图片文字&#xff0c;以下是常见的案例。 ​​热门行业解决方案 教育解决方案 教育资源不断线上化&#xff0c;使得违法违规内容风险不断提高&…

最近在西安召开的学术会议:EI检索超快,信息系统与计算技术领域!

第十二届信息系统与计算技术国际会议&#xff08;ISCTech 2024&#xff09;将于2024年11月8日-11月11日在中国西安盛大举行&#xff0c;由长沙理工大学主办&#xff0c;同济大学、西北工业大学联合协办。会议聚焦信息系统与计算技术等相关研究领域&#xff0c;广泛邀请国内外知…

货运物流App项目开发功能介绍

货运小程序通常具备多种功能&#xff0c;以便于用户管理和跟踪货物运输。以下是一些常见的功能介绍&#xff1a; 注册和登录&#xff1a; 用户可以通过手机号码或邮箱注册并登录账户。 货物发布&#xff1a; 用户可以创建货运订单&#xff0c;填写货物信息&#xff08;如品名、…

Proxmox vzdump backup ct vm

vzdump 参考 vzdump 备份参数参考 创建一键Proxmox vzdump 备份ct 虚拟机 vzdump 备份参数参考vmid 105 106 22-29行是环境变量,根据主机的实际情况更改ct 模板默认下载目录/var/lib/vz/template/cache所有备份默认目录/var/lib/vz/dumpiso 存放/var/lib/vz/template/iso# -*…

【扒代码】CCFF跨尺度特征融合

import torch import torch.nn as nn import torch.nn.functional as Fclass RepVggBlock(nn.Module):def __init__(self, ch_in, ch_out, actrelu):super().__init__()self.ch_in ch_in # 输入通道数self.ch_out ch_out # 输出通道数# 第一个卷积层&#xff0c;使用 3x3 卷…

iOS ------ UIKit相关

UIView和CALayer UIView UIView表示屏幕上的一块矩形区域&#xff0c;它是基本上iOS中所有可视化控件的父类。UIView可以管理矩形区域里的内容&#xff0c;处理矩形区域的事件&#xff0c;包括子视图的管理以及动画的实现。 UIKit相关类的继承关系 UIView继承自UIResponde…

封装加载(raect18+antd)

该组件主要是anted的组件中自带的loading属性&#xff0c; 1、封装loading组件 import React from react;function WithLoading(WrappedComponent: React.ComponentType<any>) {return (props: any) > {const [isLoading, setIsLoading] React.useState(true);Reac…

基于JAVA的高考智能排考场系统设计与实现,源码、部署+讲解

绪 论 随着教育规模的不断扩大和技术的进步&#xff0c;传统的考试管理方式面临着诸多挑战&#xff0c;如考试安排的复杂性、作弊现象的频发以及考试过程中的监督和管理等问题。因此&#xff0c;针对这些挑战&#xff0c;智能排考系统应运而生。 智能排考系统利用先进的技术…

接口基础知识5:详解request headers(一篇讲完常见字段)

课程大纲 一、请求头的定义 HTTP请求头部&#xff08;HTTP Request Headers&#xff09;&#xff1a;HTTP协议中的一部分&#xff0c;用于在客户端和服务器之间传递附加信息。这些头部字段提供了关于请求、客户端环境、或请求的上下文的信息。 请求头是键值对的形式&#xff…

day04-套餐管理

完成套餐管理模块所有业务功能&#xff0c;包括&#xff1a; 新增套餐套餐分页查询删除套餐修改套餐起售停售套餐 要求&#xff1a; 根据产品原型进行需求分析&#xff0c;分析出业务规则设计接口梳理表之间的关系&#xff08;分类表、菜品表、套餐表、口味表、套餐菜品关系…

element plus el-select修改后缀图标

使用 element plus 提供的api 默认为&#xff1a; 修改后为&#xff1a; 方法&#xff1a; <el-select v-model"value" placeholder"Select" size"large" style"width: 120px;":teleported"false" :suffix-icon"…

图数据库Neo4j的调研

图数据库Neo4j的调研 一、neo4j基础概述 概述 neo4j作为当下最热门的图数据库之一&#xff0c;他的底层实现是java语言&#xff0c;所以安装的时候必须有jre环境。并且neo4j是根据计算机中图论理论来实现的。 neo4j图数据库主要有以下组成元素&#xff1a;&#xff08;具体…

Kibana,Docker Remote Api,Kubernetes Api Server我未授权访问漏洞(附带修复方法)

一.Kibana Kibana是⼀个开源的分析与可视化平台&#xff0c;设计出来⽤于和Elasticsearch⼀起使⽤的。你可以⽤kibana搜索、查看存放在Elasticsearch中的数据。Kibana与Elasticsearch的交互⽅式是以各种不同的图表、表格、地图等直观地展示数据&#xff0c;从⽽达到⾼级的数据分…

【数据链路层】ARP协议

文章目录 以太网以太网帧对的格式 MAC地址对比MAC地址和IP地址 MTU和MSSARP协议ARP协议的工作原理ARP欺骗 以太网 ”以太网" 不是一种具体的网络, 而是一种技术标准; 既包含了数据链路层的内容, 也包含了一些物理层的内容. 例如: 规定了网络拓扑结构, 访问控制方式, 传输…