首页 > 其他分享 >[DS 小计] 树套树

[DS 小计] 树套树

时间:2024-04-07 11:22:24浏览次数:24  
标签:log 树套 int tr 小计 权值 now DS

笔者很菜,只会最简单的树状数组套权值线段树。
不是,这玩意不就套娃吗,真 ex 啊

题目简要:

  • 求 \(x\) 排名
  • 求排名为 \(x\) 的数
  • 求 \(x\) 前驱后继

我们学了权值动态开点线段树就知道这些问题乱写就行了。
但是套上 \([l,r]\) 区间呢,无修呢?

我们会主席树这些乱写就行了。

但是套上有修呢?
权值线段树乱做即可。

如果这两个一结合,树套树就出来了。

在主席树中,我们使用前缀和的思想,相减得区间。
所以如果有修改,前缀和修改是 \(O(n\log n)\) 的。
所以不要前缀和了,直接树套树。

考虑使用树状数组,每次修改改树状数组上的点就好,然后合并即可。

一句话题解:
每个树状数组里面塞一棵权值线段树,然后修改暴力修改,查询在主席树中是两个点同时跳,在树套树中就是 \(\log n\) 个点同时跳。

于是就做完了。
时间复杂度 \(O(n\log n\log w)\)

点击查看代码
#include<bits/stdc++.h>
#define ls(x) tr[x].l
#define rs(x) tr[x].r
#define N 50005
#define ll long long
using namespace std;
const int M=1e8+1;
int n,m;
int a[N];
int root[N];
struct tnode{
	int l,r,v;
}tr[N*405];
int tot;
int q[N],lp,lq,p[N];
void modify(int &now,int l,int r,int p,int v)
{
	if(!now) now=++tot;
	tr[now].v+=v;
	if(l==r)return;
	int mid=(l+r)/2;
	if(p<=mid) modify(ls(now),l,mid,p,v);
	else modify(rs(now),mid+1,r,p,v);
}
int query(int now,int l,int r,int L,int R)
{
	if(!now) return 0;
	if(l>R||r<L) return 0;
	if(l>=L&&r<=R) return tr[now].v;
	int mid=(l+r)/2;
	return query(ls(now),l,mid,L,R)+query(rs(now),mid+1,r,L,R);
}
int Kquery(int l,int r,int k)
{
	if(l==r) return l;
	int mid=(l+r)/2,lv=0;
	for(int i=1;i<=lp;i++) lv-=tr[ls(p[i])].v;
	for(int i=1;i<=lq;i++) lv+=tr[ls(q[i])].v;
	if(k<=lv)
	{
		for(int i=1;i<=lp;i++) p[i]=ls(p[i]);
		for(int i=1;i<=lq;i++) q[i]=ls(q[i]);
		return Kquery(l,mid,k);
	}
	else
	{
		for(int i=1;i<=lp;i++) p[i]=rs(p[i]);
		for(int i=1;i<=lq;i++) q[i]=rs(q[i]);
		return Kquery(mid+1,r,k-lv);
	}
}
void add(int x,int v,int w)
{
	while(x<=n)
	{
		modify(root[x],0,M,v,w);
		x+=x&-x;
	}
}
void updata(int x,int v,bool tag=1)
{
	if(tag) add(x,a[x],-1); 
	add(x,v,1);
	a[x]=v;
}
void pre_query(int l,int r)
{
	lp=lq=0;
	l--;
	while(l)
	{
		p[++lp]=root[l];
		l-=l&-l;
	}
	while(r)
	{
		q[++lq]=root[r];
		r-=r&-r;
	}
}
int grank(int l,int r,int x)
{
	pre_query(l,r);
	int res=0;
	while(lp) res-=query(p[lp--],0,M,0,x-1);
	while(lq) res+=query(q[lq--],0,M,0,x-1);
	return res+1;
}
int kth(int l,int r,int k)
{
	pre_query(l,r);
	return Kquery(0,M,k);
}
int gnext(int l,int r,int x,int p)
{
	int k;
	if(p) k=grank(l,r,x+1);
	else k=grank(l,r,x)-1;
	if(k<1) return -2147483647;
	if(k>r-l+1) return 2147483647;
	return kth(l,r,k);
}
int main() 
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		int v;
		scanf("%d",&v);
		updata(i,v,0);
	}
	while(m--)
	{
		int opr,l,r,k;
		scanf("%d%d%d",&opr,&l,&r);
		if(opr^3) scanf("%d",&k);
		if(opr==1) printf("%d\n",grank(l,r,k));
		if(opr==2) printf("%d\n",kth(l,r,k));
		if(opr==3) updata(l,r);
		if(opr==4) printf("%d\n",gnext(l,r,k,0));
		if(opr==5) printf("%d\n",gnext(l,r,k,1));
	}
	return 0;
}

自我感觉已经很短了。

标签:log,树套,int,tr,小计,权值,now,DS
From: https://www.cnblogs.com/g1ove/p/18118703

相关文章

  • AndroidStudio学习记录(4):单选按钮控件RadioButton
    用于应用二选一等多选选项的设置<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical">&l......
  • DISTILLM: Towards Streamlined Distillation for Large Language Models
    本文是LLM系列文章,针对《DISTILLM:TowardsStreamlinedDistillationforLargeLanguageModels》的翻译。DISTILLM:面向大型语言模型的流线蒸馏摘要1引言2背景3DISTILLM4实验5分析与讨论6相关工作7结论摘要知识蒸馏(KD)被广泛用于将教师模型压缩为......
  • 基于STC8H8K64U和DS18B20的温度采集和LabVIEW上位机显示
    之前通过STC单片机和DS18B20实现了环境温度采集并串口显示,后面进一步想要实现温度的实时监测和数据记录保存,因此编写了LabVIEW程序,修改了部分单片机程序代码。经过实验验证,该项目可以实现LabVIEW上位机对MCU发送指令,MCU通过DS18B20温度传感器获取环境温度,并通过串口......
  • 折腾PXE网络启动 pxe 双引导bios&uefi模式 WDS windows deployment server
    简介:这才是最终章。折腾这么多,其实还是为了WDS。折腾TFTPD引导bios,是为了确认引导文件可以引导maxdos。折腾TFTPD引导uefi,也是为了确认可以引导grub。折腾OPENWRT双引导bios和UEFI,是为了确认DHCPoption93。现在我们有了可以双引导的TFTP-ROOT目录,虽然只有4个文件,这足够我......
  • [DS 小计] 李超线段树
    前言大家好啊,今天讲的是LCT(李超Tree)(bushi错了错了。这两不是一个东西。概念李超树能干什么。插入一条直线/线段单点查询当前点的峰值(最大最小均可)你会说:OI中有什么是和斜率相关的吗?有,那就是斜率优化。关于斜率优化可以看这个。你会说:你说的对,静态的dp......
  • CF1149D Abandoning Roads 题解
    Description一张\(n\)个点\(m\)条边的无向图,只有\(a,b\)两种边权(\(a<b\)),对于每个\(i\),求图中所有的最小生成树中,从\(1\)到\(i\)距离的最小值。\(2\leqn\leq70,n-1\leqm\leq200,1\leqa<b\leq10^7\)。Solution先考虑一个最小生成树是什么样的形态,显然保留边权......
  • CF1200E Compress Words 题解
    题目链接:CF或者洛谷注意到总字符串长度不超过\(1e6\),对于两个串之间找前后缀匹配,只要能暴力枚举长度,\(check\为\O(1)\),那么最后显然线性复杂度。可以考虑\(kmp\),也可以考虑字符串哈希,最好上双哈希,然后拼串显然是在尾部继续添加新的前缀哈希,这个需要添加的串可以单独由匹配......
  • AndroidStudio学习记录(3):操纵按钮控件Botton、ImageBotton
    按钮控件是平时看到的,常用Botton和ImageButton控件,一般操纵按钮来实现相应的命令,比如在手机上的查找登录注册,以及点击命令等等。ImaBotton与Button的区别在于它没有文本,只有图片,需要制定图片路径在activity_main.xml文件中,它们是这样使用的:<?xmlversion="1.0"encoding=......
  • BNDS 2024/4/6模拟赛题解
    T1方程描述给出非负整数\(N\),统计不定方程\(X+Y^2+Z^3=N\)的非负整数解\((X,Y,Z)\)的数量。输入输入数据,包含一个非负整数\(N\)。输出输出数据,包含一个非负整数表示解的数量。数据范围40%的数据,\(N<=10000\)60%的数据,\(N<=10^8\)100%的数据,\(N<=10^{16}\)分析......
  • AbstractQueuedSynchronizer源码分析
    在分析Java并发包java.util.concurrent源码的时候,少不了需要了解AbstractQueuedSynchronizer(以下简写AQS)这个抽象类,因为它是Java并发包的基础工具类,是实现ReentrantLock、CountDownLatch、Semaphore、FutureTask等类的基础。在分析Java并发包java.util.concurren......