1. 程式人生 > >簡單資料結構練習題OJ

簡單資料結構練習題OJ

A、最小值維護

時間限制: 1 Sec  記憶體限制: 128 MB

題目描述

設計一個數據結構,支援以下兩種操作:

1. 插入一個數

2. 輸出並刪除其中最小的數 

 

輸入

輸入檔案的第一行為 n,代表操作的個數。
接下來有 n 行,每行包含一個操作,操作可能是以下兩種格式:

1. ADD number,表示插入數字 “number”。
2. RELEASE MIN,表示輸出當前資料結構中的最小值並將其刪去。 

 

輸出

對於每一個 RELEASE MIN 操作,如果當前資料結構內沒有元素,輸出 一行字串"ERROR",否則輸出一行一個整數,代表當前的最小值。 

 

樣例輸入

7 ADD 9 ADD 2 RELEASE MIN ADD 1 RELEASE MIN RELEASE MIN RELEASE MIN

樣例輸出

2 1 9 ERROR

提示

 



 

對於所有資料,滿足 n ≤ 200000, number 在 32 位有符號整形的表 示範圍之內。 

 

裸的堆

#include<cstdio>
#include<queue>
using namespace std;
 
int n,x;
priority_queue<int,vector<int>,greater<int> >q; 
char s[1000];
 
int main()
{
    scanf("%d\n",&n);
    while(n--)
    {
        scanf("%s",s+1);
        if(s[1]=='A') 
        {
            scanf("%d",&x);
            q.push(x);
        }else
        {
            scanf("%s",s+1);
            if(q.empty()) printf("ERROR\n");
                else printf("%d\n",q.top()),q.pop();
        }
    }
    return 0;
}

 

B、

線段

時間限制: 1 Sec  記憶體限制: 128 MB

題目描述

考慮一些在實數軸上的線段,你需要寫一個程式處理以下兩種詢問:

1. 詢問 + L R 增加一條線段 [L, R],你的程式應該輸出有多少條線段被 該線段包含(非嚴格)。

2. 詢問 - L R 刪除線段 [L, R],如果這條線段不存在則忽略這個詢問。 

 

輸入

輸入檔案的每一行都包含一個詢問,格式如題目所述,你的程式應該 處理到檔案結束為止。 

 

輸出

對於每一個 “+” 詢問,輸出一個整數,代表被該線段包含的線段條 數。 

 

樣例輸入

+ 1 2 + 1 2 + 0 3 - 1 2 + 1 2

樣例輸出

0 1 2 1

提示

 



 

對於所有資料,詢問的個數不超過 25000 個,任意時刻數軸上的線段 不超過 1000 條, L, R 均在 32 位有符號整數的表示範圍之內。 

 

暴力,但據說正解是線段樹

#include<cstdio>
using namespace std;
int n,ans;
const int N=1e5+5;
int l[N],r[N];
char s[N];
int main()
{
    while(scanf("%s",s+1)!=EOF)
    {
        if(s[1]=='+')
        {
            n++;
            scanf("%d%d",&l[n],&r[n]);
            ans=0;
            for(int i=1;i<n;i++)
                if(l[i]>=l[n]&&r[i]<=r[n]) ans++;
            printf("%d\n",ans);
        }else
        {
            int ll,rr;
            scanf("%d%d",&ll,&rr);
            int loc=0;
            for(int i=1;i<=n;i++)
                if(ll==l[i]&&rr==r[i]) 
                {
                    loc=i; break;
                }   
            if(loc) 
            {
                for(int i=loc;i<n;i++)
                    l[i]=l[i+1],r[i]=r[i+1];
                n--;
            }
        }
    }
    return 0;
}

 

C、維護集合

時間限制: 1 Sec  記憶體限制: 512 MB

題目描述

維護一個字串集合:初始為空,依次處理一些插入操作,並在插入 之後輸出該字串在集合中出現的次數。 

 

輸入

輸入檔案包含若干行,每行為一個字串,依次代表一個待插入的字 符串。該字串一定非空,且僅包含英文字母和數字。 

 

輸出

對於每個插入操作輸出一行一個整數,代表插入該字串之後,該字 符串在集合中出現的次數。 

 

樣例輸入

str1 str2 str1 str1 str2 str3

樣例輸出

1 1 2 3 2 1

提示

 



 

字串的長度不超過 100,字串個數不超過 100000。 

 

裸的Hash,實測單Hash會被卡,所以要雙Hash+map,儲存用pair

#include<cstdio>
#include<iostream>
#include<cstring>
#include<map>
#define ll long long
using namespace std;
const int p1=6662333,p2=1e9+7;
map<pair<int,int>,int>a;
char s[1001];
int main()
{
    while(scanf("%s",s+1)!=EOF){
        int len=strlen(s+1);
        ll t1=0,t2=0;
        for(int i=1;i<=strlen(s+1);i++)
            (t1=t1*201+s[i])%=p1,
            (t2=t2*202+s[i])%=p2;
        a[make_pair(t1,t2)]++;
        printf("%d\n",a[make_pair(t1,t2)]);
    }
    return 0;
}

 

D、維護圖的連通性

時間限制: 1 Sec  記憶體限制: 128 MB

題目描述

給定一個無向圖 G,寫一個程式處理以下兩種操作:

1. 刪去一條邊 (u, v)

2. 詢問兩點 u,v 是否連通 

 

輸入

輸入檔案的第一行包含三個整數 n,m,q,依次代表圖的頂點數、邊數、 詢問的個數。

接下來 m 行,每行兩個整數 u,v,描述圖中的一條邊 (u, v)。接下來 q 行,每行三個整數 t,u,v,描述一個操作。若 t = 1 則操作代表刪去邊 (u, v),否則操作代表詢問點 u 和 v 是否連通。資料保證刪除的邊一定存 在。 

 

輸出

對於每個詢問操作輸出一行字串 “Yes”(連通)或者 “No”(不連通)。 

 

樣例輸入

3 2 4 1 2 2 3 2 1 2 1 1 2 2 1 3 2 2 3

樣例輸出

Yes No Yes

提示


 

對於所有的資料, n ≤ 1000, m ≤ 100000, q ≤ 100000,可能存在重邊。 

看見刪邊,下意識想到倒著做然後加邊,再用並查集維護即可

然而陣列開小了,GG

#include<cstdio>
using namespace std;
int read()
{
    int ret=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9')
        ret=(ret<<1)+(ret<<3)+ch-'0',
        ch=getchar();
    return ret;
}
 
const int N=1005;
int n,m,q,f[N][N],ff[N],top,ans[1000005];
struct NA{
    int t,u,v;
}e[1000005];
 
int find(int x)
{
    return x==ff[x]?x:ff[x]=find(ff[x]);
}
int main()
{
    n=read(),m=read(),q=read(); 
    for(int i=1;i<=m;i++)
    {
        int u=read(),v=read();
        f[u][v]++,f[v][u]++;
    }
    for(int i=1;i<=q;i++)
    {
        e[i].t=read();
        e[i].u=read(),e[i].v=read();
        if(e[i].t==1)
            f[e[i].u][e[i].v]--,f[e[i].v][e[i].u]--;
    }
    for(int i=1;i<=n;i++) ff[i]=i;
    for(int i=1;i<=n;i++)
        for(int j=1;j<i;j++)
            if(f[i][j]) 
            {
                int f1=find(i),f2=find(j);
                if(f1!=f2) ff[f1]=f2;
            }
    for(int i=q;i;i--)
    {
        int u=e[i].u,v=e[i].v;
        if(e[i].t==1)
        {
            int f1=find(u),f2=find(v);
            if(f1!=f2) ff[f1]=f2;
        }else
        {
            top++;
            if(find(u)==find(v)) ans[top]=1;
                else ans[top]=0;
        }
    }   
    for(int i=top;i;i--)
    {
        if(ans[i]) printf("Yes\n");
            else printf("No\n");
    }
    return 0;
}

 

E、計算字尾表示式

時間限制: 1 Sec  記憶體限制: 128 MB 

題目描述

字尾表示式是將運算子置於兩個運算物件之後的一種表達方法,例如 “3+4” 用寫成字尾表示式後就是 “3 4 +”,而 “3-4*5” 寫成字尾表示式之後 是 “3 4 5 * -”,“(3-4)*5” 寫成字尾表示式之後是 “3 4 - 5 *”。

  寫一個程式,讀入一個字尾表示式,計算它的值。 

 

輸入

輸入僅有一行,為待求值的字尾表示式,每兩個操作符或者數字之間 用一個空格隔開。資料保證不需要判錯,且中間結果可以使用 32 位有符號 整數表示。

  輸入的表示式中僅包含加減乘除四種運算子,且除號代表整除。 

 

輸出

輸入一個整數,為字尾表示式的值。 

 

樣例輸入

3 4 - 5 *

樣例輸出

-5

提示

對於所有資料表示式的長度不超過 100000,且一定為合法表示式。 

用棧模擬一下即可

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int top;
int st[1000000];
char s[1000000];
int main()
{
    top=0;
    while(scanf("%s",s+1)!=EOF)
    {
        if(s[1]=='+')
        {
            st[top-1]=st[top-1]+st[top];
            top--;
        }else
        if(s[1]=='*')
        {
            st[top-1]=st[top-1]*st[top];
            top--;
        }else
        if(s[1]=='/')
        {
            st[top-1]=st[top-1]/st[top];
            top--;
        }else
        if(s[1]=='-')
        {
            if(strlen(s+1)==1) 
            {
                st[top-1]=st[top-1]-st[top];
                top--;
                continue;
            } else
            {
                top++; st[top]=0;
                for(int i=2;i<=strlen(s+1);i++)
                    st[top]=(st[top]<<1)+(st[top]<<3)+s[i]-'0';
                st[top]=-st[top];
            }
        }else
        if(s[1]>='0'&&s[1]<='9') 
        {
            top++; st[top]=0;
            for(int i=1;i<=strlen(s+1);i++)
                st[top]=(st[top]<<1)+(st[top]<<3)+s[i]-'0';
                 
        }
    }
    printf("%d\n",st[1]);
    return 0;
}

F、表示式的值

時間限制: 1 Sec  記憶體限制: 128 MB

此題請翻看前面的部落格

G、關押罪犯

翻看後面的部落格,謝謝