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
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;
}
时间限制: 1 Sec 内存限制: 128 MB
此题请翻看前面的博客
翻看后面的博客,谢谢