P2286 [HNOI2004] 宠物收养场
P2286 [HNOI2004] 宠物收养场
题目翻译:
给定 \(n\) 次操作,每次操作会添加一个元素。并且维护一个集合,若当前添加的元素与集合中元素种类相同,则直接添加,若不相同这要将最终答案加上给元素与集合中元素的差的绝对值的最小值,并删除对应的集合中的元素。(特别注意:若有两个元素与添加元素的差相同,则删除较小的那个)
思路:
若要找到一个与添加元素最接近的元素,且可以随意删除添加,很容易想到平衡树。我们维护一个平衡树,在查询的时候直接找前驱和后继,求最小值然后,删除即可。对于两种不同种类的元素,我们只需要用一个变量 \(op\) 维护当前集合中的元素类型,并用 \(cnt\) 变量维护当前集合中元素个数,这样每次添加元素时,若 \(cnt=0\) 就给 \(op\) 赋值为当前元素类型,即可。
完整代码:
#include<bits/stdc++.h>
#define fa(x) tr[(x)].fa
#define lc(x) tr[(x)].s[0]
#define rc(x) tr[(x)].s[1]
using namespace std;
const int N=1e5+10;
const int P=1000000;
struct tree{
int s[2],fa,siz,key;
tree(){s[0]=s[1]=fa=siz=key=0;}
}tr[N];
int rt,idx;
void pushup(int x){
tr[x].siz=tr[lc(x)].siz+tr[rc(x)].siz+1;
}
int newnode(int key){
tr[++idx].key=key;
tr[idx].siz=1;
return idx;
}
int get(int x){
return x==rc(fa(x));
}
void clear(int x){
lc(x)=rc(x)=fa(x)=tr[x].siz=tr[x].key=0;
}
void rotate(int x){
int y=fa(x),z=fa(y),c=get(x);
if(tr[x].s[c^1])tr[tr[x].s[c^1]].fa=y;
tr[y].s[c]=tr[x].s[c^1];
tr[x].s[c^1]=y;
fa(y)=x;
fa(x)=z;
if(z)tr[z].s[y==rc(z)]=x;
pushup(y);
pushup(x);
}
void splay(int x){
for(int f=fa(x);f=fa(x),f;rotate(x)){
if(fa(f))rotate(get(x)==get(x)?f:x);
}
rt=x;
}
void ins(int key){
int now=rt,f=0;
while(now){
f=now;
now=tr[now].s[key>tr[now].key];
}
now=newnode(key);
tr[f].s[key>tr[f].key]=now;
fa(now)=f;
splay(now);
}
int pre(int key){
int now=rt,f=0,ans=0;
while(now){
f=now;
if(tr[now].key>key){
now=lc(now);
}
else{
ans=tr[now].key;
now=rc(now);
}
}
splay(f);
return ans;
}
int nxt(int key){
int now=rt,f=0,ans=0;
while(now){
f=now;
if(tr[now].key<key){
now=rc(now);
}
else{
ans=tr[now].key;
now=lc(now);
}
}
splay(f);
return ans;
}
void del(int key){
int now=rt,f=0;
while(now && key!=tr[now].key){
f=now;
now=tr[now].s[key>tr[now].key];
}
if(!now){
splay(f);
return;
}
splay(now);
int cur=lc(now);
if(!cur){
rt=rc(now);
fa(rt)=0;
clear(now);
return;
}
while(rc(cur)){
cur=rc(cur);
}
fa(rc(now))=cur;
rc(cur)=rc(now);
fa(lc(now))=0;
clear(now);
pushup(cur);
splay(cur);
}
int main(){
ins(+214748364);
ins(-214748364);
int n;
scanf("%d",&n);
int op,w,now,ans=0,cnt=0;
for(int i=1;i<=n;i++){
scanf("%d%d",&op,&w);
if(cnt==0){
now=op;
}
if(op==now){
ins(w);
cnt++;
}
else{
int w1=pre(w),w2=nxt(w);
//cout<<w1<<" "<<w2<<endl;
if(abs(w-w1)<=abs(w-w2)){
ans+=abs(w-w1);
ans%=P;
cnt--;
del(w1);
}
else{
ans+=abs(w-w2);
ans%=P;
cnt--;
del(w2);
}
}
}
printf("%d",ans);
}
平衡树讲解
本文作者:XichenOC
本文链接:https://www.cnblogs.com/XichenOC/p/18688603
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步