本題splay基本操作:
1.如果是左跳,比如從 x 左跳到 y,就相當於查詢 [ y, x ) 區間的最大值,那麼就把 y-1 伸展到根,把 x 伸展到根的右節點,那麼根的右節點的左節點對應的就是這段區間。
1.如果是右跳,比如從 x 右跳到 y,就相當於查詢 ( x, y ] 區間的最大值,那麼就把 x 伸展到根,把 y+1 伸展到根的右節點,那麼根的右節點的左節點對應的就是這段區間。
3.這裡 splay 是要將某個位置的節點伸展到給定位置,所以採用從頂向下查詢第 rank 個的方式伸展,見**。
4.remove操作:刪除第 k 個,就把第 k-1 個伸展到根,把第 k+1 個伸展到根的右節點,刪除它的左節點即可。別忘記 update 操作。
5.insert操作:如果要插到第 k 處,就把第 k-1 個節點旋轉到根,把第 k 個節點旋轉到根的右節點,那麼插入到根的右節點的左節點就可以代替原來的第 k 個。好像沒必要像我分兩種情況。最後別忘 update,先子節點再根節點。
6.move操作:就是先 remove 再 insert。
7.巨集定義:因為用到大量的根節點的左右節點的呼叫,而這裡還不適合用引用,所以乾脆定義了巨集,簡單清楚,程式設計效果好了很多。
8.邊界防溢位:因為1、2中的將 y-1、y+1 伸展到根都是危險操作,因為 y 有可能等於 1 或 n,而 0 節點不能成為根節點,因為0節點預設為空;n+1 節點直接溢位,所以建立兩個虛擬節點,乙個為1,乙個為 n+1,分別放在開頭和末尾,對程式設計本身沒影響,但不用擔心溢位了,不過各個節點相應的位置就變了,讀入位置 x 後 x++ 就行了。
總時間耗費: 6439ms
總記憶體耗費: 3 kb
有些慢,但記憶體耗的很少。
#include#includeusing namespace std;
const int inf = 1e9 + 7;
const int maxn = 100000 + 10;
int root, ch[maxn][2], v[maxn], s[maxn], maxv[maxn];
void update(int o)
int cmp(int o, int k)
void rotate(int& o, int d)
void splay(int& o, int k)
rotate(o, d^1);
}void build(int l, int r, int pa)
int m = (l+r) >> 1; maxv[m] = v[m];
build(l, m-1, m); build(m+1, r, m); update(m);
if(m < pa) ch[pa][0] = m; else ch[pa][1] = m;
}#define lc ch[root][0]
#define rc ch[root][1]
void move(int x, int y) else
}int main()
case 'd':
} }return 0;
}
1343 例4 2 牛的旅行
農民john的農場裡有很多牧區。有的路徑連線一些特定的牧區。一片所有連通的牧區稱為乙個牧場。但是就目前而言,你能看到至少有兩個牧區不連通。現在,john想在農場裡新增一條路徑 注意,恰好一條 對這條路徑有這樣的限制 乙個牧場的直徑就是牧場中最遠的兩個牧區的距離 本題中所提到的所有距離指的都是最短的距...
1343 例4 2 牛的旅行
弗洛伊德演算法 1 弗洛伊德演算法求出任意兩點間的最短路,然後求出每個點到所有可到達點的最大距離,記為 m i 2 r1 max m i 3 列舉不聯通的兩個點 i j,把它們聯通,則新的直徑是m i m j dist i,j 4 r2 min m i m j dist i j 5 re max r...
UVa 1343 旋轉遊戲(dfs IDA )
題意 如圖所示,一共有8個1,8個2和8個3,如何以最少的移動來使得中間8個格仔都為同乙個數。思路 狀態空間搜尋問題。用ida 演算法的話會比較快,而且 比較簡潔。ida 的關鍵就是要尋找乙個估價函式h 在這道題目中,每次移動最多隻會使乙個格仔的數字正確,所以當maxd d 1 include2 i...