简单数据结构练习题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
#include
using namespace std;
 
int n,x;
priority_queue,greater >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
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=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

 

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
#include
#include
#include
#define ll long long
using namespace std;
const int p1=6662333,p2=1e9+7;
map,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
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

 

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
#include
#include
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、关押罪犯

翻看后面的博客,谢谢

你可能感兴趣的:(栈,Hash,堆,并查集)