這道算是一道合格的splay基礎題。距離上一次那道簡單的splay時間比較長,因為經歷了元旦晚會和之後的乙個小假期沒寫題。
這道題涵蓋的splay的操作還是比較多的,適合練手。寫的時候思路一定要清晰,否則不好調。
推薦自頂向下寫。我就是先寫的最大的框架,判斷輸入,呼叫哪個函式。寫出大框架之後就輪到挨個寫函式了,這些函式也是有上下關係的,最靠上的當然就是最直接的對應每個操作的函式。我使用**和合併操作來完成它們。這樣很簡單地寫完了這些函式。之後就該寫其下一層的**和合併,其中涉及到splay,pushdown和maintain,思路清晰,很快寫好。之後寫下一層的splay,這個函式寫得很簡短,就用到了rotate。再最後,就應該寫最底層的pushdown,maintain,rotate和find。一氣呵成,寫完**大概用了1個小時多一點。
然而,除錯的過程有一點坎坷(被cogs坑了一下,本地怎麼跑都沒事,cogs上就是全t,完全沒有輸出,加了記憶體池優化空間後在bzoj上是過了)。細節較多的是mx的維護,在maintain中需要注意一下。還有就是maintain的呼叫的時間,以及呼叫時要保證合法性(比如偷懶的我在maintain裡沒有判斷lc和rc是否為0就直接拿它們更新rt,那麼就要保證lc或rc是0的時候的su,ml,mr,mx不會影響到rt)。
#include
#include
#include
#include
using namespace std;
void get (int &x)
while (c <= '9' && c >= '0') x = x
*10+c-48, c = getchar();
if (neg) x = -x;
}void get (char *s)
void put (int
x) char s[15]; int num = 0;
while (x) s[++num] = (x
%10)+48, x /= 10;
while (num) putchar(s[num--]);
putchar ('\n');
}int max (int a, int b, int c, int d, int e)
queue mem;
struct node
};struct splaytree
if (p[rt].re)
}//int va, lc, rc, fa, sz, ch, re, su, ml, mr, mx;
void maintain (int rt)
int makenewtree (int tot)
int find (int rt, int k)
void reuse (int rt)
void rotate (int rt)
else
if(p[gfa].lc == fa) p[gfa].lc=rt; else p[gfa].rc=rt;
p[rt].fa = gfa;
maintain(fa); maintain(rt);
}void splay (int rt)
}int
split (int rt, int op) // 1 left 0 right
void merge (int l, int r)
if (!r)
root = l;
splay (find(root,p[root].sz));
pushdown(root);
p[root].rc = r, p[r].fa = root;
maintain(root);
}void insert (int
pos, int tot)
}void erase (int
pos, int tot)
else
}void update (int
pos, int tot)
void rever (int
pos, int tot)
void getsum (int
pos, int tot)
int op = split (find(root,pos),1);
int op2= split (find(root,tot),0);
put (p[root].su);
merge (root,op2);
merge (op, root);
}void maxsum (int
pos, int tot)
}solve;
int n, m;
int getcommand()
int main()
if (cmd == 1) solve.insert(pos, tot);
if (cmd == 2) solve.erase (pos, tot);
if (cmd == 3) solve.update(pos, tot);
if (cmd == 4) solve.rever (pos, tot);
if (cmd == 5) solve.getsum(pos, tot);
if (cmd == 0) solve.maxsum(pos, tot);
}return
0;}
BZOJ1500 NOI2005 維修數列
description input 輸入檔案的第1行包含兩個數n和m,n表示初始時數列中數的個數,m表示要進行的運算元目。第2行包含n個數字,描述初始時的數列。以下m行,每行一條命令,格式參見問題描述中的 output 對於輸入資料中的get sum和max sum操作,向輸出檔案依次列印結果,每個...
bzoj1500 NOI2005 維修數列
splay鼻祖級的題目?霧。insert 把第pos個數 有哨兵節點 轉到root,把第pos 1個數轉到root的右兒子,然後對c建樹然後把這棵樹插到root右兒子的左兒子處 delete 把第pos個數轉到root,把第pos tot 1個數轉到root右兒子,刪掉root右兒子的左兒子 變成0...
BZOJ 1500 NOI2005 維修數列
輸入的第1 行包含兩個數n 和m m 20 000 n 表示初始時數列中數的個數,m表示要進行的運算元目。第2行包含n個數字,描述初始時的數列。以下m行,每行一條命令,格式參見問題描述中的 任何時刻數列中最多含有500 000個數,數列中任何乙個數字均在 1 000,1 000 內。插入的數字總數不...