一、
835. Trie字符串统计
- 题目
- 提交记录
- 讨论
- 题解
- 视频讲解
维护一个字符串集合,支持两种 *** 作:
I x
向集合中插入一个字符串 xx;Q x
询问一个字符串在集合中出现了多少次。
共有 NN 个 *** 作,输入的字符串总长度不超过 105105,字符串仅包含小写英文字母。
输入格式
第一行包含整数 NN,表示 *** 作数。
接下来 NN 行,每行包含一个 *** 作指令,指令为 I x
或 Q x
中的一种。
输出格式
对于每个询问指令 Q x
,都要输出一个整数作为结果,表示 xx 在集合中出现的次数。
每个结果占一行。
数据范围
1≤N≤2∗1041≤N≤2∗104
输入样例:
5
I abc
Q abc
Q ab
I ab
Q ab
输出样例:
1
0
1
trie树:
思路:看完之后有几个点容易搞乱,需要注意
1.idx是个很神奇的标记符号,当输入一个字符时,只有唯一对应的idx标记对应这个字符,将此时的idx标记放在cnt数组中就可以知道哪个已经存在哪个没有存在;当该字符已经在该位置存在时,idx不会++,顺着走看看是否存在该字符串,如果存在,idx一次都不++,但凡不存在一次都会++,idx递增的特性致使他的唯一对应性
2.如果该结点是没有东西的,赋予此时的a[p][t]一个值,该值决定下一行走向,如果已经有东西,则顺着原来的走到下一个结点;直到遍历成功
3.复做易错:应该是cnt[p]++,而我经常写成cnt[idx]++;
#include
using namespace std;
#include
#include
#define N 1000010
int a[N][26],cnt[N],idx;
void Insert(string str)
{
int p=0;
for(int i=0;str[i];i++)
{
int t=str[i]-'a';
if(!a[p][t])a[p][t]=++idx;
p=a[p][t];
}
cnt[p]++;
}
int query(string str)
{
int p=0;
for(int i=0;str[i];i++)
{
int t=str[i]-'a';
if(!a[p][t])return 0;
p=a[p][t];
}
return cnt[p];
}
int main()
{
int n;
cin>>n;
while(n--)
{
char a;
cin>>a;
string op;
cin>>op;
if(a=='I')
{
Insert(op);
}
else if(a=='Q')
{
cout<
---------------------------------------------------------------------------------------------------------------------------------
二、
836. 合并集合
- 题目
- 提交记录
- 讨论
- 题解
- 视频讲解
一共有 nn 个数,编号是 1∼n1∼n,最开始每个数各自在一个集合中。
现在要进行 mm 个 *** 作, *** 作共有两种:
M a b
,将编号为 aa 和 bb 的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个 *** 作;Q a b
,询问编号为 aa 和 bb 的两个数是否在同一个集合中;
输入格式
第一行输入整数 nn 和 mm。
接下来 mm 行,每行包含一个 *** 作指令,指令为 M a b
或 Q a b
中的一种。
输出格式
对于每个询问指令 Q a b
,都要输出一个结果,如果 aa 和 bb 在同一集合内,则输出 Yes
,否则输出 No
。
每个结果占一行。
数据范围
1≤n,m≤1051≤n,m≤105
输入样例:
4 5
M 1 2
M 3 4
Q 1 2
Q 1 3
Q 3 4
输出样例:
Yes
No
Yes
并查集:
注意点:记住Find函数
1.只有当p[x]=x时,x才是根节点
2.开始 *** 作前先将所有节点作为根结点
#include
using namespace std;
#include
#include
#define N 1000010
int p[N];
int Find(int x)
{
if(p[x]!=x)p[x]=Find(p[x]);
return p[x];
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
p[i]=i;
}
while(m--)
{
char op[2];
int a,b;
scanf("%s%d%d",op,&a,&b);
if(op[0]=='M')
{
p[Find(a)]=Find(b);
}
else
{
if(Find(a)==Find(b))
cout<<"Yes"<
---------------------------------------------------------------------------------------------------------------------------------
三、
837. 连通块中点的数量
- 题目
- 提交记录
- 讨论
- 题解
- 视频讲解
给定一个包含 nn 个点(编号为 1∼n1∼n)的无向图,初始时图中没有边。
现在要进行 mm 个 *** 作, *** 作共有三种:
C a b
,在点 aa 和点 bb 之间连一条边,aa 和 bb 可能相等;Q1 a b
,询问点 aa 和点 bb 是否在同一个连通块中,aa 和 bb 可能相等;Q2 a
,询问点 aa 所在连通块中点的数量;
输入格式
第一行输入整数 nn 和 mm。
接下来 mm 行,每行包含一个 *** 作指令,指令为 C a b
,Q1 a b
或 Q2 a
中的一种。
输出格式
对于每个询问指令 Q1 a b
,如果 aa 和 bb 在同一个连通块中,则输出 Yes
,否则输出 No
。
对于每个询问指令 Q2 a
,输出一个整数表示点 aa 所在连通块中点的数量
每个结果占一行。
数据范围
1≤n,m≤1051≤n,m≤105
输入样例:
5 5
C 1 2
Q1 1 2
Q2 1
C 2 5
Q2 5
输出样例:
Yes
2
3
注意点:sizes相加时记得加Find,讲sizes存在每个并查集的头节点
#include
using namespace std;
#include
#include
#define N 1000010
int p[N],sizes[N];
int Find(int x)
{
if(p[x]!=x)p[x]=Find(p[x]);
return p[x];
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
p[i]=i;
sizes[i]=1;
}
while(m--)
{
char str[5];
int a,b;
scanf("%s",str);
if(str[0]=='C')
{
scanf("%d%d",&a,&b);
if(Find(a)==Find(b))continue;
sizes[Find(b)]+=sizes[Find(a)];
p[Find(a)]=Find(b);
}
else if(str[1]=='1')
{
scanf("%d%d",&a,&b);
if(Find(a)==Find(b))cout<<"Yes"<
---------------------------------------------------------------------------------------------------------------------------------
小根堆:
1.插入一个数:将其放在最后一位一直向上即可
2.求最小值 :第一个数时小根堆最小值
3.删除最小值:将第一个数与最后一个数互换,然后向下维护即可
4.删除任意元素:将其与最后一个数呼唤,同时执行向下向上 *** 作,如果较大,则会执行down不执行up,反之
5.修改任意元素:和4同理
---------------------------------------------------------------------------------------------------------------------------------
四、
838. 堆排序
- 题目
- 提交记录
- 讨论
- 题解
- 视频讲解
输入一个长度为 nn 的整数数列,从小到大输出前 mm 小的数。
输入格式
第一行包含整数 nn 和 mm。
第二行包含 nn 个整数,表示整数数列。
输出格式
共一行,包含 mm 个整数,表示整数数列中前 mm 小的数。
数据范围
1≤m≤n≤1051≤m≤n≤105,
1≤数列中元素≤1091≤数列中元素≤109
输入样例:
5 3
4 5 1 3 2
输出样例:
1 2 3
思路:明天补充。
#include
#include
using namespace std;
const int N = 100010;
int h[N], mySize;
int n, m;
void down(int u)
{
int t = u;
if (2 * u <= mySize && h[t] > h[2 * u])
t = 2 * u;
if (2 * u + 1 <= mySize && h[t] > h[2 * u + 1])
t = 2 * u + 1;
if (u != t)
{
swap(h[u], h[t]);
down(t);
}
}
int main()
{
cin >> n >> m;
mySize = n;
for (int i = 1; i <= n; i++)
scanf("%d", &h[i]);
for (int i = n / 2; i; i--)
down(i);
while (m--)
{
cout << h[1] << " ";
h[1] = h[mySize--];
down(1);
}
return 0;
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)