[luogu2286][HNOI2004]寵物收養場【平衡樹】
阿新 • • 發佈:2019-04-02
int class 傳送門 get 快速 總結 noi tor www
分析一下
不定長數組
但是vector很容易溢出,長度一大,很有可能就RE,那個時候想哭都沒時間哭了。
值來維護平衡樹的平衡性。
代碼實現非常的簡單,但是我打的比較冗長。
那麽再回到這一道題目,如果我們只需要建立兩個平衡樹。(其實一棵就足夠了,因為一棵有節點的時候另外一棵一定是沒有節點的。)
每一次找前驅和後繼,判斷更加接近的那一個,更新答案,並刪除前驅或者是後繼。
如果樹為空或者是己方的樹有節點,那麽就直接插入。
【傳送門】
前言
這一篇題解並不是為了講什麽算法,只是總結一下平衡樹在OI考試中的註意事項。
題意簡化(給不想看題目的小夥伴們一點福利)
給你兩堆數,每一次給你一個數,每一次在另外一堆數中找到這個數的前綴後繼,刪去前驅後繼中較靠近的,得到了分數為兩個數的差的絕對值。請你讓這個分數最小。
(題意簡化的應該不能在簡化了吧qwq)
做法1&&2&&3(非正常做法)
我們都知道,所有的平衡樹的題目都可以用不定長數組vector
和不允許重復元素的set
或者是允許重復元素的muliset
來實現。
這個東西在考場上是救命的,如果你剩下的時間不多了,那麽是在不行就用以上的辦法來偏分。
vector
和set
和muliset
的優缺點。不定長數組
vector
實現起來非常的簡單,只要你熟悉指針和vector
的正常操作。但是vector很容易溢出,長度一大,很有可能就RE,那個時候想哭都沒時間哭了。
#include <bits/stdc++.h> using namespace std; int n; vector<int>v; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { int op=0,x=0; scanf("%d%d",&op,&x); if(op==1) v.insert(upper_bound(v.begin(),v.end(),x),x); else if(op==2) v.erase(lower_bound(v.begin(),v.end(),x)); else if(op==3) printf("%d\n",lower_bound(v.begin(),v.end(),x)-v.begin()+1); else if(op==4) printf("%d\n",v[x-1]); else if(op==5) printf("%d\n",*--lower_bound(v.begin(),v.end(),x)); else if(op==6) printf("%d\n",*upper_bound(v.begin(),v.end(),x)); } return 0; }
實現非常的簡單,但是需要註意指針的變換。
但是這一道題目我們用vector,蒟蒻我用了差不多5s才跑出大的數據。(數據從LOJ上來的)
所以set
和muliset
可以更加快速的完成我們的任務。
set
差別並不是太大,一個可以實現沒有重復的,一個實現有重復的。
來自chhokmah的實測,set比muliset要快。
所以總結一下:
- vector好寫,但是容易錯,不推薦使用。
- set可以實現無重復,推薦使用。
- muliset可以實現有重復,推薦使用。
做法4正常的平衡樹
這裏以treap為例。
簡單介紹一下treap,treap是tree和heap的結合,每一次我們需要用自己給節點附加的rd
代碼實現非常的簡單,但是我打的比較冗長。
那麽再回到這一道題目,如果我們只需要建立兩個平衡樹。(其實一棵就足夠了,因為一棵有節點的時候另外一棵一定是沒有節點的。)
每一次找前驅和後繼,判斷更加接近的那一個,更新答案,並刪除前驅或者是後繼。
如果樹為空或者是己方的樹有節點,那麽就直接插入。
#include <bits/stdc++.h>
#define N 80005
#define mod 1000000
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
template <typename T>
inline void read(T &x) {
x = 0; T fl = 1; char ch = 0;
for (; ch < '0' || ch > '9'; ch = getchar())
if (ch == '-') fl = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar())
x = (x << 1) + (x << 3) + (ch ^ 48);
x *= fl;
}
struct Treap {
int tot, rt;
struct Node {
int cnt, sz, rd, ch[2], val;
void Init (int Val) { val = Val; ch[0] = ch[1] = 0; cnt = sz = 1; rd = rand() % 100; }
} tr[N];
Treap() { tot = 0; memset(tr, 0, sizeof(tr)); }
void pushup (int nod) { tr[nod].sz = tr[tr[nod].ch[0]].sz + tr[tr[nod].ch[1]].sz + tr[nod].cnt; }
void rotate(int &nod, int d) {
int k = tr[nod].ch[d ^ 1]; tr[nod].ch[d ^ 1] = tr[k].ch[d]; tr[k].ch[d] = nod;
pushup(nod); pushup(k); nod = k;
}
void ins(int &nod, int val) {
if (!nod) nod = ++ tot, tr[nod].Init(val);
else if (val == tr[nod].val) tr[nod].sz ++, tr[nod].cnt ++;
else {
int d = (val > tr[nod].val);
ins(tr[nod].ch[d], val);
if (tr[nod].rd < tr[tr[nod].ch[d]].rd) rotate(nod, d ^ 1);
pushup(nod);
}
}
void del(int &nod, int val) {
if (!nod) return;
if (val < tr[nod].val) del(tr[nod].ch[0], val);
else if (val > tr[nod].val) del(tr[nod].ch[1], val);
else {
if (!tr[nod].ch[0] && !tr[nod].ch[1]) {tr[nod].sz --, tr[nod].cnt --; if (tr[nod].cnt == 0) nod = 0;}
else if (tr[nod].ch[0] && !tr[nod].ch[1]) { rotate(nod, 1) ; del(tr[nod].ch[1], val);}
else if (!tr[nod].ch[0] && tr[nod].ch[1]) { rotate(nod, 0); del(tr[nod].ch[0], val); }
else {
int d = tr[tr[nod].ch[0]].rd > tr[tr[nod].ch[1]].rd;
rotate(nod, d); del(tr[nod].ch[d], val);
}
}
}
int pre(int nod, int val) {
if (!nod) return -inf;
if (tr[nod].val > val) return pre(tr[nod].ch[0], val);
else return max(tr[nod].val , pre(tr[nod].ch[1], val));
}
int suc(int nod, int val) {
if (!nod ) return inf;
if (tr[nod].val < val) return suc(tr[nod].ch[1], val);
else return min(tr[nod].val, suc(tr[nod].ch[0], val));
}
}Pet, Cus;
int n;
ll ans = 0ll;
int main () {
srand(19260817);
read(n);
while (n --) {
int opt, x; read(opt); read(x);
if (opt == 0) { // Pet
if (Cus.rt == 0) Pet.ins(Pet.rt, x);
else {
int lst = Cus.pre(Cus.rt, x), nxt = Cus.suc(Cus.rt, x);
if (abs(x - lst) <= abs(nxt - x)) { Cus.del(Cus.rt, lst); ans = (ans + 1ll * abs(x - lst)) % mod; }
else { Cus.del(Cus.rt, nxt); ans = (ans + 1ll * abs(nxt - x)) % mod;}
}
}
else { // Customer
if (Pet.rt == 0) Cus.ins(Cus.rt, x);
else {
int lst = Pet.pre(Pet.rt, x), nxt = Pet.suc(Pet.rt, x);
if (abs(x - lst) <= abs(nxt - x)) { Pet.del(Pet.rt, lst); ans = (ans + 1ll * abs(x - lst)) % mod; }
else { Pet.del(Pet.rt, nxt); ans = (ans + 1ll * abs(nxt - x)) % mod;}
}
}
}
printf("%lld\n", ans % mod);
return 0;
}
[luogu2286][HNOI2004]寵物收養場【平衡樹】