**倉庫
前言這題做法很多。 1.雙端佇列 + 啟發式合併. 2.list 3.無向圖模擬 4.splay.5.treap
題目大意鏈結
方法一:雙端佇列 + 啟發式合併
題目看起來就是個大模擬.發現關鍵點:拼接完之後會整體反轉.那麼我們自然想到了用雙端佇列,維護乙個映象即可(思路可見this)。但是遇到了第乙個問題:卡空間.那麼我們不能直接用deq
ue
deque
dequ
e.有兩種解決方法:
1.手寫雙端佇列,動態開記憶體且每次及時**lbi
l_lb
i的記憶體.
2.使用list代替deq
ue
deque
dequ
e.因為我們不需要o(1
)o(1)
o(1)
的隨機訪問佇列。所以用鍊錶實現雙端佇列是一樣的。而且使用的記憶體空間小很多。因為鍊錶會動態的申請和銷毀節點.
第二個問題:超時.
這麼模擬嚴格來講可以將複雜度卡到o(n
2)
o(n^2)
o(n2
).但是我們發現每次是將乙個鍊錶拼接到另乙個鍊錶,並且拼接的鍊錶會被清空.那麼意味著整個過程總節點數是不變的.那麼自然我們可以想到啟發式合併.複雜度o(n
logn
)o(nlogn)
o(nlog
n).證明過程類似並查集的啟發式合併.
然後還需要注意乙個問題:
操作是有方向性的.如果實際是大sz 合併到 小sz中.我們得反著來.所以還得對映一下索引.
令i d(
i)
id(i)
id(i
)代表第i
ii個佇列實際儲存在下標為id(
i)
id(i)
id(i
)的佇列中.上面那種情況我們就得swa
p(id
(小的)
,id(
大的))
swap(id(小的) , id(大的))
swap(i
d(小的
),id
(大的)
).**見**倉庫1.1
方法二:list模擬
這個方法實際上就是上面那個方法的改進版.其他細節都一樣.因為我們發現既然都已經用了鍊錶了,就沒有必要再模擬它的過程乙個乙個將lbi
l_lb
i取出來再放到lai
l_la
i裡去了.可以直接將表頭轉接一下就好了.
所以還是對每個鍊錶維護乙個映象版本.然後根據題目的那個操作的特性稍微討論一下就好了.
複雜度:o(n
)o(n)
o(n)
.這裡學習到乙個新的stl函式:spl
ic
esplice
splice
,其作用是o(1
)o(1)
o(1)
時間完成鍊錶的拼接.並且將拼接的鍊錶刪除.
用法:x.splice(x.end() , y) – 使用後x = x + y, y = empty
**見**倉庫2.1
方法三:無向圖dfs模擬(待補)
方法四:splay/fhqtreap解法
這種方法非常顯然,直接利用特性翻轉模擬即可.複雜度控制在o(n
logn
)o(nlogn)
o(nlog
n).**見**倉庫4.1
**倉庫
1.1
list<
int> q[maxn][2
];bool tag[maxn]
;int id[maxn]
;int
main()
for(
int i =
1; i <= m ; i++
)swap
(id[x]
, id[y]);
}else
tag[c]
=!tag[c];}
}printf
("%d "
, q[id[1]
][tag[id[1]
]].size()
);while
(q[id[1]
][tag[id[1]
]].size()
)printf
("\n");
}return0;
}
2.1list<
int> q[maxn][2
];intmain()
for(
int i =
1; i <= m ; i++
)printf
("%d "
, q[1]
[1].
size()
);while
(q[1][
1].size()
)printf
("\n");
}return0;
}
3.1
4.1
#include
using
namespace std;
#define ll long long
#define pii pair
#define pb push_back
#define mp make_pair
#define vi vector
#define vll vector
#define fi first
#define se second
const
int maxn =
1e5+5;
const
int mod =
1e9+7;
struct node
fhq[maxn]
;int cnt , rt[maxn]
;mt19937 rnd
(233);
int newnode (
int val)
void pushup (
int x)
void pushdown (
int x)
// 將now這個子樹按sz分成兩個部分,sz部分接在x,大於部分接在y
void split (
int now ,
int sz ,
int&x ,
int&y)
pushdown
(now);if
(fhq[fhq[now]
.l].sz < sz)
else
pushup
(now);}
int mer (
int x ,
int y)
pushdown
(y);
fhq[y]
.l =
mer(x , fhq[y]
.l);
pushup
(y);
return y;
}void dfs (
int now)
intmain()
for(
int i =
1; i <= m ; i++
)printf
("%d "
, fhq[rt[1]
].sz)
;dfs
(rt[1]
);printf
("\n");
}return0;
}
真金不怕火練 如何用雙向鍊錶實現LRU淘汰機制演算法
無論是應屆生的春招 秋招還是社招,難以避免的一關都是要面對面試官來幾個手撕演算法,如果你參加過幾次面試,就知道鍊錶出現的頻率是極其高的。那麼本章將提高一點難度,為你介紹常見的鍊錶演算法,包括一些 bat 等大廠的筆試面試題,同時最後彩蛋裡將詳細的介紹可以稱之為鍊錶筆試面試史上最難的一道題 lru 淘...
每日一練(12) 鍊錶中倒數第k個節點
title 每日一練 12 鍊錶中倒數第k個節點 categories 劍指offer tags 每日一練 date 2022 01 25 輸入乙個鍊錶,輸出該鍊錶中倒數第k個節點。為了符合大多數人的習慣,本題從1開始計數,即鍊錶的尾節點是倒數第1個節點。例如,乙個鍊錶有 6 個節點,從頭節點開始,...
刪除單鏈表和雙向鍊錶倒數第k個節點
注釋 當從鍊錶第乙個開始讀,直到讀到最後乙個,讓k不斷地減一。k 0說明沒什麼可以刪的,返回head即可,k 0,說明刪頭節點,k 0時,再從頭開始讀,k逐漸 1,直到k 0,那個便是要刪除的前乙個節點 public class node public static node removelastk...