牛客练习赛73 D-离别(线段树+离线)

这篇博客介绍了如何使用队列和线段树数据结构来解决区间查询和区间更新的问题。具体策略是通过预处理找出每个位置i的可行区间[l[i], r[i]],然后用线段树维护区间内的左边界数量,从而快速回答区间查询。在处理过程中,队列用于存储相同值的下标,根据队列大小调整左边界,并更新右边界。最后,通过排序询问区间并依次处理,得到每个查询的答案。

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

题目链接:https://ac.nowcoder.com/acm/contest/9033/D

思路:预处理出区间右边界为i时,左边界的可取范围[ l[i],r[i] ]。具体就是用队列来存储值为a[i]的下标,先把i放入队列中。如果队列里的下标大于k个,那么,l[i] q.front()+1l[i-1](区间要满足第i-1的值的区间)的较大值,并且队首出列。如果,队列里的下标等于k个,r[i] 为q.front()r[i-1]的较大值。对询问区间的右端点从小到达排序,线段树维护当前询问所有可取的区间的左端点的个数,区间更新,区间查询。

#include <bits/stdc++.h>
#define ll long long
#define lson (cur<<1)
#define rson (cur<<1|1)
using namespace std;
const int N = 3e5+10;
int n,m,k,a[N],l[N],r[N];
queue<int> qu[N];
struct Node{
	int id,l,r;
	bool operator <(const Node & a){
		return r<a.r;
	}
}q[N];
struct node{
	int l,r,lazy;
	ll sum;
}tree[N<<2];
ll ans[N];
void build(int cur,int l,int r){
	tree[cur].l=l,tree[cur].r=r;
	if(l==r) return;
	int m=(l+r)>>1;
	build(lson,l,m);
	build(rson,m+1,r);
}
void pushdown(int cur){
	if(tree[cur].lazy){
		tree[lson].lazy+=tree[cur].lazy,tree[rson].lazy+=tree[cur].lazy;
		
		tree[lson].sum+=1LL*(tree[lson].r-tree[lson].l+1)*tree[cur].lazy;
		tree[rson].sum+=1LL*(tree[rson].r-tree[rson].l+1)*tree[cur].lazy;
		tree[cur].lazy=0;
	}
}
void pushup(int cur){
	tree[cur].sum=tree[lson].sum+tree[rson].sum;
}
void update(int cur,int pl,int pr){
	if(pl<=tree[cur].l&&tree[cur].r<=pr){
		tree[cur].lazy++;
		tree[cur].sum+=1LL*(tree[cur].r-tree[cur].l+1);
		return ;
	}
	pushdown(cur);
	if(pl<=tree[lson].r) update(lson,pl,pr);
	if(pr>=tree[rson].l) update(rson,pl,pr);
	pushup(cur);
}
ll query(int cur,int pl,int pr){
	if(pl<=tree[cur].l&&tree[cur].r<=pr){
		return tree[cur].sum;
	}
	pushdown(cur);
	ll res=0;
	if(pl<=tree[lson].r) res+=query(lson,pl,pr);
	if(pr>=tree[rson].l) res+=query(rson,pl,pr);
	return res;
	pushup(cur);
}
int main(void){
	scanf("%d%d%d",&n,&m,&k);
	l[0]=1;
	for(int i=1;i<=n;i++){
		l[i]=l[i-1],r[i]=r[i-1];
		scanf("%d",&a[i]); 
		qu[a[i]].push(i);
		int siz=qu[a[i]].size();
		if(siz>k){
			l[i]=max(l[i],qu[a[i]].front()+1);
			qu[a[i]].pop(),siz--;
		}
		if(siz==k)
			r[i]=max(r[i],qu[a[i]].front());
	}
	for(int i=1;i<=m;i++){
		scanf("%d%d",&q[i].l,&q[i].r);
		q[i].id=i;
	}
	sort(q+1,q+1+m);
	build(1,1,n);
	int pos=1;
	for(int i=1;i<=m;i++){
		while(pos<=q[i].r){
			if(r[pos]) update(1,l[pos],r[pos]);
			pos++;
		}	
		ans[q[i].id]=query(1,q[i].l,q[i].r);
	}
	for(int i=1;i<=m;i++)
		printf("%lld\n",ans[i]);
	return 0;	
} 

 

此压缩包包含了本毕业设计项目的完整内容,具体包括源代码、毕业论文以及演示PPT模板。 开发语言:Java 框架:SSM(Spring、Spring MVC、MyBatis) JDK版本:JDK 1.8 或以上 开发工具:Eclipse 或 IntelliJ IDEA Maven版本:Maven 3.3 或以上 数据库:MySQL 5.7 或以上 项目配置完成后即可运行,若需添加额外功能,可根据需求自行扩展。 运行条件 确保已安装 JDK 1.8 或更高版本,并正确配置 Java 环境变量。 使用 Eclipse 或 IntelliJ IDEA 打开项目,导入 Maven 依赖,确保依赖包下载完成。 配置数据库环境,确保 MySQL 服务正常运行,并导入项目中提供的数据库脚本。 在 IDE 中启动项目,确认所有服务正常运行。 主要功能简述: 请假审批流程:系统支持请假申请的逐级审批,包括班主任审批和院系领导审批(针对超过三天的请假)。学生可以随时查看请假申请的审批进展情况。 请假记录管理:系统记录学生的所有请假记录,包括请假时间、原因、审批状态及审批意见等,供学生和审批人员查询。 学生在线请假:学生可以通过系统在线填写请假申请,包括请假的起止日期和请假原因,并提交给班主任审批。超过三天的请假需经班主任审批后,再由院系领导审批。 出勤信息记录:任课老师可以在线记录学生的上课出勤情况,包括迟到、早退、旷课和请假等状态。 出勤信息查询:学生、任课老师、班主任、院系领导和学校领导均可根据权限查看不同范围的学生上课出勤信息。学生可以查看自己所有学年的出勤信息,任课老师可以查看所教班级的出勤信息,班主任和院系领导可以查看本班或本院系的出勤信息,学校领导可以查看全校的出勤信息。 出勤统计与分析:系统提供出勤统计功能,可以按班级、学期等条件统计学生的出勤情况,帮助管理人员了解学生的出勤状况。 用户管理:系统管理员负责管理所有用户信息,包括学生、任课老师、班主任、院系领导和学校领导的账号创建、权限分配等。 数据维护:管理员可以动态更新和维护系统所需的数据,如学生信息、课程安排、学年安排等,确保系统的正常运行。 系统配置:管理员可以对系统进行配置,如设置数据库连接参数、调整系统参数等,以满足不同的使用需求。 身份验证:系统采用用户名和密码进行身份验证,确保只有授权用户才能访问系统。不同用户类型(学生、任课老师、班主任、院系领导、学校领导、系统管理员)具有不同的操作权限。 权限控制:系统根据用户类型分配不同的操作权限,确保用户只能访问和操作其权限范围内的功能和数据。 数据安全:系统采取多种措施保障数据安全,如数据库加密、访问控制等,防止数据泄露和非法访问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值