首页 > 其他分享 >基础线段树相关

基础线段树相关

时间:2024-07-17 17:30:48浏览次数:14  
标签:res int tr 线段 基础 return 权值 相关

权值线段树

线段树在这里作为前置知识,我们就不说了,而且权值线段树也不是核心内容,不会大篇幅讲。

首先,权值线段树在维护什么?维护的是桶。

然后,权值线段树有什么用?可以求一些序列的第 \(k\) 大之类的问题。

于是我们放个板子题。

第 k 小整数

简单题,直接看代码和注释就行,当然也可以使用线性的快速选择算法。

事实上,权值线段树左,右边界为 \([l,r]\) 的节点在这里维护的是区间 \([l,r]\) 内的数的个数(但是要去重)。

代码:

#include<bits/stdc++.h>
#define int long long
#define N 300005
using namespace std;
int n,k,a[N],tr[N<<2];
void pushup(int u){
	tr[u]=tr[u<<1]+tr[u<<1|1];
}
void build(int u,int l,int r){
	if(l==r){
		tr[u]=a[l];//大小为这个元素的桶
		return;
	}
	int mid=l+r>>1;
	build(u<<1,l,mid);
	build(u<<1|1,mid+1,r);
	pushup(u);
}
int qry(int u,int l,int r,int k){
	if(l==r)return l;
	int mid=l+r>>1;
	if(tr[u<<1]>=k)return qry(u<<1,l,mid,k);//如果左子树总个数更大,那么答案在左子树里
	else return qry(u<<1|1,mid+1,r,k-tr[u<<1]);//否则在右子树里,但是我们需要减掉左子树的大小
}
signed main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		int x;
		cin>>x;
		if(a[x]==0)a[x]++;//这里多个看成一个,所以只统计一次
	}
	a[30000]++;//放一下哨兵
	build(1,1,30000);
	int res=qry(1,1,30000,k);
	if(res==30000)cout<<"NO RESULT";
	else cout<<res;
	return 0;
}

线段树合并

基础概念没啥好说的,就是合并两颗线段树。所以直接看题。

Promotion Counting P

一道裸题。显然权值数量可以合并,所以我们对每个点建立一颗权值线段树,然后跑一遍 \(dfs\),在回溯的时候合并和求答案。

然后我们怎么求答案?显然地,我们查一下权值线段树中权值比他大的数的数量就行了。

直接看代码:

#include<bits/stdc++.h>
#define int long long
#define N 200005
using namespace std;
int n,p[N],a[N],res[N],rt[N];
int h[N],e[N],ne[N],idx,cnt;
struct node{
	int l,r,sum;
}tr[N<<4];
void add(int a,int b){
	e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
void modify(int &u,int l,int r,int x){
	if(l>r)return;
	u=++cnt;//动态开点
	if(l==r){
		tr[u].sum++;
		return;
	}
	int mid=l+r>>1;
	if(x<=mid)modify(tr[u].l,l,mid,x);//如果在左区间里,插入到左子树
	else modify(tr[u].r,mid+1,r,x);//否则插入到右子树
	tr[u].sum=tr[tr[u].l].sum+tr[tr[u].r].sum;//数量就是两边加起来
}
int qry(int u,int l,int r,int x){
	if(!u)return 0;
	if(l>=x)return tr[u].sum;//如果区间内最小数已经不小于目标值,返回数量
	int res=0;
	int mid=l+r>>1;
	if(mid>=x)res+=qry(tr[u].l,l,mid,x);//如果左子树里面的数可能比目标值大就递归
	res+=qry(tr[u].r,mid+1,r,x);
	return res;
}
int merge(int x,int y){
	if(!x||!y)return x+y;//返回非空的一边
	tr[x].l=merge(tr[x].l,tr[y].l);
	tr[x].r=merge(tr[x].r,tr[y].r);//合并两棵树
	tr[x].sum=tr[tr[x].l].sum+tr[tr[x].r].sum;//数量合并同上
	return x;
}
void dfs(int u){
	for(int i=h[u];~i;i=ne[i]){
		int j=e[i];
		dfs(j);
		rt[u]=merge(rt[u],rt[j]);//在dfs时合并
	}
	res[u]=qry(rt[u],1,n,a[u]+1);//查询比这个数大的数的数量
}
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>p[i];
		a[i]=p[i];
	}
	sort(p+1,p+n+1);
	int len=unique(p+1,p+n+1)-p-1;
	for(int i=1;i<=n;i++){
		a[i]=lower_bound(p+1,p+len+1,a[i])-p;//离散化
	}
	memset(h,-1,sizeof h);
	for(int i=2;i<=n;i++){
		int x;
		cin>>x;
		add(x,i);
	}
	for(int i=1;i<=n;i++){
		modify(rt[i],1,n,a[i]);//先把每个数开一颗权值线段树
	}
	dfs(1);
	for(int i=1;i<=n;i++){
		cout<<res[i]<<'\n';
	}
	return 0;
}

雨天的尾巴

标签:res,int,tr,线段,基础,return,权值,相关
From: https://www.cnblogs.com/zxh923aoao/p/18305608

相关文章

  • Java语言基础-03
    1.Scanner接收用户输入的数据:packageday04;importjava.util.Scanner;//1.导入一个扫描仪//Scanner的演示publicclassScannerDemo{publicstaticvoidmain(String[]args){//创建类CommandBySwitch,接收用户输入的命令command(int),并输出......
  • iOS开发基础124-RunLoop实现卡顿检测
    利用RunLoop实现卡顿检测的基本思路是通过监听RunLoop的状态变化来判断主线程的执行时长。如果RunLoop在某个状态停留的时间超过了预设的时间阈值,则认为发生了卡顿。在具体实现中,可以利用CFRunLoopObserver来监听RunLoop的状态变化,并记录时间差。一、卡顿检测的基本原......
  • iOS开发基础122-RunLoop
    深入探讨RunLoop的底层实现需要了解CoreFoundation框架中的CFRunLoop以及与RunLoop工作机制紧密相关的操作系统底层API。这些底层实现主要涉及到事件源、定时器和线程的调度机制。本文将深入剖析RunLoop的底层结构及其运行流程。一、RunLoop底层数据结构涉及RunLo......
  • iOS开发基础123-自动释放池
    自动释放池(AutoreleasePool)是Objective-C中用于管理内存的一个重要机制,它帮助开发者简化内存管理的工作。自动释放池的核心概念是将对象放入池中,在某个时刻由系统统一释放这些对象。这种机制在iOS和macOS的应用开发中广泛使用,尤其是在事件循环和线程运行时。为了深入理解其底层......
  • 从零开始学Python第一天:基础知识
    前言在这个信息爆炸的时代,编程技能已经成为我们生活和工作中不可或缺的一部分。而Python,作为一门简洁易读、功能强大的编程语言,正逐渐受到越来越多人的青睐。作为初学者,你可能会对编程充满好奇与期待,同时也有一些担忧和困惑。但是请相信,只要你愿意付出努力和时间,Python的......
  • 基础知识(JAVA入门)
    常用的CMD命令盘符名称+冒号说明:盘符切换dir说明:查看当前路径下的内容cd说明:进入单级目录cd..说明:回退到上一级目录cd目录1\目录2....说明:进入多级目录cls说明:清屏exit说明:退出命令提示符窗口环境变量我们想要在任意的目录下都可以打开指定的软件。就可以把软件的路......
  • python基础语法
    一、python常用内置对象1、常量与变量常量即字面值无法改变的量,例如一个确定的数字、列表、字符串,如“Helloworld”就是一个典型的字符串常量,变量是指值可以发生改变的量,在python中,不仅变量的值可以任意变化,变量的值也可以随时发生改变。这是因为python变量并不直接存储值,而是......
  • iOS开发基础119-组件化
    一、引言组件化是将应用程序分解成多个独立模块的设计方法,这些模块可以单独开发、测试和维护。对于大型iOS项目,组件化能够提高开发效率、降低耦合、增加代码复用性,并且使项目更易维护。本文将详细介绍如何在iOS项目中实现组件化,包括本地组件管理和远程组件管理。二、为什么......
  • iOS开发基础120-通知与线程
    NSNotificationCenter是iOS和macOS开发中用于消息传递的机制,可以在多个对象之间实现解耦的事件通知。理解NSNotificationCenter的线程模型对正确使用这一工具至关重要。NSNotificationCenter的线程模型1.消息发送线程当你通过NSNotificationCenter发送消息时,消息会......
  • DevOps系列七(Jenkins实现基础CD操作)
    一、Jenkins实现基础CD操作1.1Jenkins配置参数化构建1.2添加一个标签1.3指定代码版本在打包之前加上一个命令将代码版本切换到制定的位置gitcheckout$tag应用并保存。1.4仓库代码打标签改动提交代码后,再创建一个tag,此时,我们就有两个tag了1.5构建回到jenkins......