1. 程式人生 > 其它 >Acwing 第二章 資料結構

Acwing 第二章 資料結構

單調佇列

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;
}