Acwing 第二章 資料結構
阿新 • • 發佈:2022-03-18
單調佇列
154. 滑動視窗
用一個佇列維護窗口裡面的所有值
當即將入隊的佇列比隊尾元素小時,就讓隊尾元素出隊,迴圈直到大於等於隊尾元素時,停止,因為沒有用
求最大值與該思想類似
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N = 1e6 + 10; int n,k; int a[N]; int q[N];//佇列儲存的是下標 int main() { scanf("%d%d", &n, &k); for (int i = 0; i < n; i ++ ) { cin>>a[i]; } int hh = 0,tt = -1; for (int i=0;i<n;i++) //單調佇列處理最小值 { if(hh<=tt && i - q[hh] + 1 > k) hh++; //維護當前視窗元素個數與k一致 while(hh<=tt && a[i] <= a[q[tt]]) tt--; //刪去冗餘元素,注意是從隊尾刪除 q[++tt] = i; //新元素入隊 if(i+1>=k) cout<<a[q[hh]]<<' '; //i要足夠大才能輸出最值 } puts(""); hh = 0,tt = -1; for (int i = 0; i < n; i ++ ) //單調佇列處理最大值 { if(hh<=tt && i - q[hh] + 1 > k) hh++; while(hh<=tt && a[i] >= a[q[tt]]) tt--; q[++tt] = i; if(i+1>=k) cout<<a[q[hh]]<<' '; } return 0; }
字典樹(Trie)
835. Trie字串統計
Trie:高效的儲存和查詢字串集合的資料結構
#include <iostream> #include <cstring> #include <algorithm> #include <unordered_map> using namespace std; const int N = 2e4+10; int son[N][26],idx;//son陣列表示字典樹,idx表示層數索引 int cnt[N];//以當前結點結尾的單詞數量 char x[N]; char op[2]; void insert(char s[]) { int cur = 0;//表示當前位於第幾層 for(int i=0;s[i]!='\0';i++) { int t = s[i] - 'a'; if(!son[cur][t]) son[cur][t] = ++idx; //沒有路徑就創造路徑,注意是++idx //idx是下一字母的層數 cur = son[cur][t]; } cnt[cur]++;//更新以該結點結尾的單詞數量 } int query(char s[]) { int cur = 0;//表示當前位於第幾層 for(int i=0;s[i]!='\0';i++) { int t = s[i] - 'a'; if(!son[cur][t]) return 0;//不存在路徑,直接返回0 cur = son[cur][t]; } return cnt[cur]; } int main() { int n; cin >> n; for (int i = 0; i < n; i ++ ) { cin>>op>>x; if(op[0] == 'I') { insert(x); } else cout<<query(x)<<endl; } return 0; }
並查集
240. 食物鏈
帶權並查集
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N = 50005; int n,k,c,x,y; int p[N],d[N]; int ans; int find(int x) { int t = p[x]; if(p[x]!=x) { p[x] = find(p[x]); d[x] += d[t]; //維護距離,find前表示到父節點的距離,find後表示到祖宗結點的距離 } return p[x]; } int main() { scanf("%d%d", &n, &k); for (int i = 1; i <= n; i ++ ) { p[i] = i; } while(k--) { cin>>c>>x>>y; if(x>n||y>n) { ++ans; continue; } int px = find(x),py = find(y); if(c==1) //同類,距離取餘3為0 { if(px == py && (d[x] - d[y]) % 3 != 0) ans++; //同一集合但距離mod3不為0,假話 else if(px!=py) //不同集合,則是真話,合併它們並用距離表示同類關係 { p[px] = py; d[px] = d[y] - d[x]; } } else //x吃y,距離取餘3為1 { if(px == py && (d[x] - d[y] - 1) % 3 !=0) ans++; //同一集合但距離mod3不為1,假話 else if(px != py) //不同集合,則是真話,合併它們並用距離表示捕食關係 { p[px] = py; d[px] = d[y] - d[x] + 1; } } } cout<<ans<<endl; return 0; }
字串雜湊
841. 字串雜湊
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10,P = 131;
typedef unsigned long long ULL;
ULL h[N],p[N];
int n,m;
char str[N];
ULL get(int l,int r)
{
return h[r] - h[l-1] * p[r-l+1]; //取區間字串的雜湊值 h[r] - h[l-1] * p^(r-l+1)
}
int main()
{
scanf("%d%d%s", &n, &m,str+1);
p[0] = 1;
for (int i = 1; i <= n; i ++ )
{
p[i] = p[i-1] * P; //預處理P的n次冪
h[i] = h[i-1] * P + str[i]; //計算雜湊值
}
while (m -- )
{
int l1,r1,l2,r2;
scanf("%d%d%d%d", &l1, &r1,&l2,&r2);
if(get(l1,r1) == get(l2,r2)) puts("Yes");
else puts("No");
}
return 0;
}