一,概述
set,不可重结合(保序)
- 底层实现: 红黑树
- 插入复杂度: O ( l o g N ) O(log N) O(logN)
- 优势:在只须前驱后继时和大量平衡树开设需求时
multiset 可重集(保序)
二,例题
P5250 【深基17.例5】木材仓库
一个木材仓库,里面可以存储各种长度的木材,但是保证没有两个木材的长度是相同的。
作为仓库负责人,你有时候会进货,有时候会出货,因此需要维护这个库存。有不超过 100000 条的操作:
- 进货,格式
1 Length
:在仓库中放入一根长度为 Length(不超过 1 0 9 10^9 109) 的木材。如果已经有相同长度的木材那么输出Already Exist
。 - 出货,格式
2 Length
:从仓库中取出长度为 Length 的木材。如果没有刚好长度的木材,取出仓库中存在的和要求长度最接近的木材。如果有多根木材符合要求,取出比较短的一根。
输出取出的木材长度。如果仓库是空的,输出Empty
。
#include<bits/stdc++.h>
using namespace std;
set<int>::iterator it1,it2 ;
set<int>s;
int main()
{
int op,n,x;
cin>>n;
while(n--)
{
cin>>op>>x;
if(op==1)
{
if(!s.insert(x).second)puts("Already Exist");
}
else
{
if(s.empty()){puts("Empty");continue;}
if(s.find(x)!=s.end()){cout<<x<<endl;s.erase(s.find(x));continue;}
it1=it2=s.lower_bound(x);
if(it1==s.begin())cout<<*it1,s.erase(it1);
else if(it1==s.end())cout<<*(-- it1),s.erase( it1);
else
{
it2 --;
if(*it1-x<x-*it2)cout<<*it1,s.erase(it1);
else cout<<*it2,s.erase(it2);
}
puts("");
}
}
}
P2161 [SHOI2009]会场预约
https://www.luogu.com.cn/problem/P2161
你需要维护一个 在数轴上的线段 的集合 SS,支持两种操作:
A l r
表示将 S S S 中所有与线段 [ l , r ] [ l , r ] [l,r][l,r] [l,r][l,r] 相交的线段删去,并将 [ l , r ] [ l , r ] [l,r][l,r] [l,r][l,r] 加入 S S S 中。B
查询 S S S 中的元素数量。- 对于
A
操作,每次还需输出删掉的元素个数。
#include<bits/stdc++.h>
#define rep(i,j,k) for(int i= j;i<=k;i++)
using namespace std;
typedef long long ll;
const int N= 1e6+9;
struct seg {int l,r; };
bool operator < (const seg&a ,const seg&b) { return a.r<b.l; }
set<seg>s;
signed main()
{
int t;
scanf("%d",&t);
while (t--)
{
char op[2];
int x,y;
scanf("%s",op);
if(*op=='A')
{
scanf("%d%d",&x,&y);
seg tem= {x,y};
int cnt= 0;
set<seg> :: iterator it;
it=s.find(tem);
while (it != s.end())
{
s.erase(it);
cnt++;
it= s.find(tem);
}
s.insert(tem);
printf("%d\n",cnt);
}
else printf("%d\n",s.size());
}
return 0;
}
P1110 [ZJOI2007]报表统计
https://www.luogu.com.cn/problem/P1110
在最开始的时候,有一个长度为 n 的整数序列 a,并且有以下三种操作:
INSERT i k
:在原数列的第 i
个元素后面添加一个新元素 k
;如果原数列的第 i
个元素已经添加了若干元素,则添加在这些元素的最后(见样例说明)。
MIN_GAP
:查询相邻两个元素的之间差值(绝对值)的最小值。
MIN_SORT_GAP
:查询所有元素中最接近的两个元素的差值(绝对值)。
#include<bits/stdc++.h>
using namespace std;
const int N= 1e6+8;
const int INF = 1e9;
multiset<int>full,delta;
int ans;
int n,m,q;
int x,z,y;
int st[N],ed[N];
void up_ans(int u)
{
auto it = full.lower_bound(u);
int nw = (*it-u);
--it;
nw = min(nw,u-*it);
ans= min(ans,nw);
full.insert(u);
}
void replac(int pos,int x)
{
delta.insert( abs( x - ed[pos] ) );
if( pos != n )
delta.erase( delta.find( abs( st[pos+1] - ed[pos] ) ) ),
delta.insert( abs( st[pos+1] - x ) );
ed[pos] = x;
}
signed main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
int u;
scanf("%d",&u);
st[i]=ed[i]=u;
}
ans = INF;
full.insert(INF);
full.insert(-INF);
for(int i=1;i<n;i++) delta.insert(abs(st[i+1]-ed[i]));
for(int i=1;i<=n;i++) up_ans(st[i]);
while (m--)
{
char op[20];
int pos,val;
scanf("%s",op);
if(op[4]=='R')
{
scanf("%d%d",&pos,&val);
up_ans(val);
replac(pos,val);
}
else if(op[4]=='G') printf("%d\n",*delta.begin());
else printf ("%d\n",ans);
}
return 0;
}
树套树简单版
一种数据结构,来维护一个长度为 n 的序列,其中需要提供以下操作:
- 1
pos x
,将pos
位置的数修改为x
。 - 2
l r x
,查询整数x
在区间[l,r]
内的前驱(前驱定义为小于x
,且最大的数)。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
const int N = 2e5+100;
const int INF = 1e9;
struct node
{
int l,r;
multiset<int>s;
}tr[N];
int w[N];
void build (int u,int l,int r)
{
tr[u]={l,r};
tr[u].s.insert(INF);
tr[u].s.insert(-INF);
for (int i = l; i <= r; i ++ ) tr[u].s.insert(w[i]);
if(l==r) return ;
int mid = (l+r)>>1;
build (u<<1,l,mid);
build (u<<1|1,mid+1,r);
}
void modify(int u,int pos,int val)
{
auto j = tr[u].s.find(w[pos]);
tr[u].s.erase(j);
tr[u].s.insert(val);
if(tr[u].l==tr[u].r && tr[u].l==pos) return;
int mid = tr[u].l+tr[u].r>>1;
if(pos<=mid)modify(u<<1,pos,val);
else modify(u<<1|1,pos,val);
}
int query(int u,int a,int b,int x)
{
if(tr[u].l >= a && tr[u].r <= b)
{
auto it = tr[u].s.lower_bound(x);
it--;
return *it;
}
int mid = tr[u].l+tr[u].r >> 1;
int res = -INF;
if(a<=mid) res=max(res,query(u<<1,a,b,x));
if(b>mid) res=max(res,query(u<<1|1,a,b,x));
return res;
}
int main()
{
int n,m;
cin >> n >> m;
for (int i = 1; i <= n; i ++ ) cin >> w[i];
build (1,1,n);
while (m -- )
{
int op,x,y,val;
scanf("%d%d%d",&op,&x,&y);
if(op==1) modify(1,x,y), w[x]=y;
else scanf("%d",&val),printf("%d\n",query(1,x,y,val));
}
return 0;
}