簡單資料結構練習題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、關押罪犯
翻看後面的部落格,謝謝