度度熊學佇列 HDU
度度熊正在學習雙端佇列,他對其翻轉和合併產生了很大的興趣。
初始時有 N 個空的雙端佇列(編號為 1 到 N ),你要支援度度熊的 Q 次操作。
①1 u w val 在編號為 u 的佇列里加入一個權值為 val 的元素。(w=0 表示加在最前面,w=1 表示加在最後面)。
②2 u w 詢問編號為 u 的佇列裡的某個元素並刪除它。( w=0 表示詢問並操作最前面的元素,w=1 表示最後面)
③3 u v w 把編號為 v 的佇列“接在”編號為 u 的佇列的最後面。w=0 表示順序接(佇列 v 的開頭和佇列 u 的結尾連在一起,佇列v 的結尾作為新佇列的結尾), w=1 表示逆序接(先將佇列 v 翻轉,再順序接在佇列 u 後面)。且該操作完成後,佇列 v 被清空。 Input 有多組資料。
對於每一組資料,第一行讀入兩個數 N 和 Q。
接下來有 Q 行,每行 3~4 個數,意義如上。
N≤150000,Q≤400000
1≤u,v≤N,0≤w≤1,1≤val≤100000
所有資料裡 Q 的和不超過500000 Output 對於每組資料的每一個操作②,輸出一行表示答案。
注意,如果操作②的佇列是空的,就輸出−1且不執行刪除操作。 Sample Input 2 10 1 1 1 23 1 1 0 233 2 1 1 1 2 1 2333 1 2 1 23333 3 1 2 1 2 2 0 2 1 1 2 1 0 2 1 1 Sample Output 23 -1 2333 233 23333
提示
由於讀入過大,C/C++ 選手建議使用讀入優化。
一個簡單的例子:
void read(int &x){ char ch = getchar();x = 0; for (; ch < ‘0’ || ch > ‘9’; ch = getchar()); for (; ch >=‘0’ && ch <= ‘9’; ch = getchar()) x = x * 10 + ch - ‘0’; }
- 題解:直接用雙向佇列進行模擬即可,熟悉一下雙向佇列的用法。注意,我在這裡面把deque放在主函式外面,開一個1.5e5的佇列會顯示超記憶體(有點不明白130M的記憶體竟然存不下。1e7的陣列在256M的情況下都是能開的(這裡很無語)),然後放在主函式裡面竟然就a了。
#include<bits/stdc++.h>
using namespace std;
int n,q;
int main(){
while(~scanf("%d %d",&n,&q)){
deque<int> sn[n+1];
while(q--){//對Q進行迴圈
int k;scanf("%d",&k);
if(k==1){//當k=1時為插入的情況
int a,b,c;scanf("%d %d %d",&a,&b,&c);
if(b){
sn[a].push_back(c);
}else{
sn[a].push_front(c);
}
}else if(k==2){//當k=2時為輸出結果的情況
int a,b;scanf("%d %d",&a,&b);
if(sn[a].empty()){
printf("-1\n");continue;
}
if(b){
printf("%d\n",sn[a].at(sn[a].size()-1));
sn[a].pop_back();
}else {
printf("%d\n",sn[a].at(0));
sn[a].pop_front();
}
}else if(k==3){//當k=3時為合併的情況
int a,b,c;scanf("%d %d %d",&a,&b,&c);
if(c==0){
while(!sn[b].empty()){
sn[a].push_back(sn[b].at(0));
sn[b].pop_front();
}
}else{
reverse(sn[b].begin(),sn[b].end());
while(!sn[b].empty()){
sn[a].push_back(sn[b].at(0));
sn[b].pop_front();
}
}
}
}
}
return 0;
}