首页 > 其他分享 >线段树合并小结

线段树合并小结

时间:2024-02-28 18:26:01浏览次数:22  
标签:lid int tr 线段 合并 mid rid 小结 sum

权值线段树

就是把线段树变成桶。

用线段树维护桶。

代码:

模板:P1138 第 k 小整数

#include<bits/stdc++.h>
using namespace std;
int n,k;
struct segmentTree{
	struct node{
		int sum;
	}tr[40000<<2];
	#define lid now<<1
	#define rid now<<1|1
	void update(int now,int l,int r,int x,int y,int k)
	{
		if(x<=l&&r<=y)
		{
			tr[now].sum=k;return ;
		}
		int mid=(l+r)>>1;
		if(x<=mid) update(lid,l,mid,x,y,k);
		if(y>mid) update(rid,mid+1,r,x,y,k);
		tr[now].sum=tr[lid].sum+tr[rid].sum; 
	}
	int query(int now,int l,int r,int k)
	{
		if(l==r) return l;
		int mid=(l+r)>>1;
		if(tr[lid].sum>=k)  query(lid,l,mid,k);
		else  query(rid,mid+1,r,k-tr[lid].sum);
	}
}st;
int cnt;
int main()
{
	cin>>n>>k;
	for(int i=1;i<=n;i++) 
	{
		int t;cin>>t;
		st.update(1,1,30000,t,t,1);
	//	cout<<"upd\n";
	}
	if(k<=0||k>=st.tr[1].sum)
	{
		cout<<"NO RESULT";return 0;
	}
	cout<<st.query(1,1,30000,k);
}

作用

  1. 查询第 \(k\) 大的数。
int kth(int now,int l,int r,int k)
{
	if(l==r) return l;
	int mid=(l+r)>>1;
	if(tr[lid].sum>=k) return kth(lid,l,mid,k);
	else return kth(rid,mid+1,r,k-tr[lid].sum);
}
  1. 算逆序对(就是模板粘上去即可)

动态开点树

可以是线段树,也可以是权值线段树。

代码:

模板: P3369 【模板】普通平衡树

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n;
int root=1,cnt=1;
int mx=2e7+1;
struct sgt{
	struct node{
		int sum,ls,rs;
	}tr[2000000<<1];
	#define lid tr[now].ls
	#define rid tr[now].rs
	void update(int &now,int l,int r,int x,int y,int k)
	{
		if(!now) now=++cnt;
		if(x<=l&&r<=y)
		{
			tr[now].sum+=k;
			return ;
		 } 
		int mid=(l+r)>>1;
		if(x<=mid) update(lid,l,mid,x,y,k);
		if(y>mid) update(rid,mid+1,r,x,y,k);
		tr[now].sum=tr[lid].sum+tr[rid].sum;
	}
	int query(int now,int l,int r,int x,int y)
	{
		if(x<=l&&r<=y) return tr[now].sum;
		int mid=(l+r)>>1,res=0;
		if(x<=mid) res+=query(lid,l,mid,x,y);
		if(y>mid) res+=query(rid,mid+1,r,x,y);
		return res; 
	}
	int kth(int now,int l,int r,int k)
	{
		if(l==r) return l;
		int mid=(l+r)>>1;
		if(tr[lid].sum>=k) return kth(lid,l,mid,k);
		else return kth(rid,mid+1,r,k-tr[lid].sum);
	}
}st;
map<int,int>mp;
signed main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		int op,t;
		scanf("%lld%lld",&op,&t);
		if(op==1)
		{
			st.update(root,-mx,mx,t,t,1);
			mp[t]++;
		}
		else if(op==2)
		{
			st.update(root,-mx,mx,t,t,-1);
			mp[t]--;
			if(!mp[t]) mp.erase(t);
		}
		else if(op==3)
		{
			cout<<st.query(root,-mx,mx,-mx,t-1)+1<<endl;
		}
		else if(op==4)
		{
			int res=st.kth(root,-mx,mx,t);
			cout<<res<<endl;
		}
		else if(op==5)
		{
			cout<<(--mp.lower_bound(t))->first<<endl;
		}
		else if(op==6)
		{
			cout<<mp.upper_bound(t)->first<<endl;
		}
	}
}
  • 要注意的一点是,\(update\) 的时候的 \(now\) 要写成 int &now 来更改值;

  • 每个操作 \(update\) 或者 \(query\) 的范围可以是负数、传进去的参数也可以是负数。

作用

缩小使用的空间。

标签:lid,int,tr,线段,合并,mid,rid,小结,sum
From: https://www.cnblogs.com/ccjjxx/p/18041355

相关文章

  • bat合并下载缓存文件
    ::进入当前bat文件所在目录cd%cd%@echooffsetlocalENABLEDELAYEDEXPANSION::设置数组obj的值setobjLentth=2setobj[0]=test1setobj[1]=test2@echo!obj[0]!@echo!obj[1]!setobjIndex=0::===在这里设置你的后缀名sethouzhui=.jpg.gif.png.m4s::===......
  • 数据结构【线段树】
    对于一个数据结构而言,我们总要能对其进行两件事:修改和操作。操作在这里是一个专有名词,专门指代求最值、求和等操作,具体能指代什么操作之后再聊。 如果朴素的用数组进行存储,那么修改是O(1)的,而操作往往是O(n)的。当操作指的是求和的时候,我们可以使用前缀和算法,前缀和使得操作是O(......
  • CCPC2023深圳 K-四国军棋(线段树维护单调栈哈希值)
    传送门解题思路对于每个人的棋子,总是最高的那个棋子发挥决定性作用,被消耗后,再看剩下的最高的棋子。这就相当于单调不递增栈的维护过程。最后就要比较两个人的单调不递增栈是否完全相同。和经典的楼房重建相似,但是这个题不止需要维护单调栈的长度,还要维护哈希值。我是分开写的......
  • CF932F Escape Through Leaf【DP,李超线段树】
    有一颗\(n\)个节点的树,根节点为\(1\)。每个节点有两个权值,第\(i\)个节点的权值为\(a_i,b_i\)。你可以从一个节点跳到它的子树内任意一个节点上。从节点\(x\)跳到节点\(y\)一次的花费为\(a_x\timesb_y\)。跳跃多次走过一条路径的总费用为每次跳跃的费用之和。求每个节......
  • 线段树合并
    线段树合并1权值线段树1.1权值线段树的基本思想权值线段树其实比较简单。正常的线段树是维护区间上每一个点的值,而权值线段树则是维护每一个数字出现的次数(可以类比为桶)。例如原本的$1-4$表示区间$[1,4]$上数字的和(或差、最大值等等),现在就表示数字$1-4$的出现次数之......
  • 概率期望小结
    P4316绿豆蛙的归宿典型的期望dp。思路就是反向建图加反向跑dp。式子是这样的:\(\largedp[v]=\sum\frac{dp[u]+w[u\to\v]}{indeg[v]}\)然后遍历图可以使用拓扑排序或者深搜。#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;intn,m;structnod......
  • Git 教程:解密 .gitignore 文件、合并分支、解决冲突、及 Git 帮助
    Git帮助如果你忘记了命令或命令的选项,你可以使用Git帮助。在命令行中,有几种不同的使用帮助命令的方式:gitcommand-help-查看特定命令的所有可用选项githelp--all-查看所有可能的命令让我们看看不同的命令。Git-help查看特定命令的选项任何时候,如果你需要帮助......
  • 古人云:时间线段树 爽!时间线段树学习笔记。
    嘛,这个东西虽然叫时间线段树,但是和线段树好像关系并不大,只是借用了一下线段树的结构。算法介绍这个算法是用来解决这类问题的:每个操作只在一段时间内生效,然后询问某个时间点所有操作的贡献。于是我们考虑离线,对整个时间序列建一个线段树,每次操作相当于是在这个线段树上进行了区......
  • LG5290/LOJ3052 春节十二响 题解(启发式合并)
    考虑当这个东西是一条链的时候我们该怎么做,显然\(1\)​会有两个儿子,然后两个儿子分别是一条链。所以我们可以给两个儿子的链上的所有节点分别加到两个堆里,每次取出两个堆的最大值加入到我们选择的答案中,然后把两个堆的最大值全部pop掉。最终的答案就是我们pop完一个堆之后,......
  • 可持久化线段树 2
    可持久化线段树前言这个东西之前讲过,但是用得少,很快就忘了。我又看了我之前的那篇笔记,简直就是胡言乱语。所了解的太浅了。最近在刷数据结构,于是决定再写一篇。但是,之前那篇不打算删了,想看黑历史的可以去看。算法概要可持久——即可以保存历史版本。我们如何得到一棵可以......