1.树的遍历

1004 Counting Leaves (30分)

基本的数据结构——树,复习了链式前向星,bfs遍历判断即可

#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <map>
#include <queue>
#include <cmath>
#define ll long long
#define inf 0x3f3f3f
#define pii pair<int, int>
using namespace std;
const int maxn = 1e4+100;
int n, m, k, par, child;
int cnt, head[maxn];
int level, ans[maxn];
struct node{
int to, nxt;
}e[maxn]; void add(int u, int v){
e[++cnt].nxt = head[u];
e[cnt].to = v;
head[u] = cnt;
}
void bfs(){
queue<pii> que;
que.push({1, 0});
while(!que.empty()){
pii tmp = que.front(); que.pop();
int u = tmp.first, step = tmp.second;
level = max(level, step);
if(head[u]){
for(int i = head[u]; i; i = e[i].nxt)
que.push({e[i].to, step+1});
}
else ans[step]++;
}
}
int main(){
scanf("%d%d", &n, &m);
while(m--){
scanf("%d%d", &par, &k);
while(k--){
scanf("%d", &child);
add(par, child);
}
}
bfs();
for(int i = 0; i <= level; i++){
printf("%d", ans[i]);
if(i!=level) printf(" ");
}
}

1053 Path of Equal Weight (30分)

树的遍历,需要思考的点在于如何记录路径并且排序输出

#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <map>
#include <queue>
#include <vector>
#include <set>
#define ll long long
#define inf 0x3f3f3f
#define pii pair<int, int>
#define pb push_back
using namespace std;
const int maxn = 1e4+100;
int n, m, s, cnt;
int val[maxn], fa[maxn];
int t, head[maxn];
vector<int> path[maxn];
struct node{
int to, nxt;
}e[maxn];
//bool cmp(vector<int> a, vector<int> b){
// reverse(a.begin(), a.end());
// reverse(b.begin(), b.end());
// return
//}
void add(int u, int v){
e[++t].to = v;
e[t].nxt = head[u];
head[u] = t;
}
void dfs(int u, int sum){
if(!head[u]&&sum==s) {
while(u!=-1) path[cnt].pb(val[u]), u = fa[u];
reverse(path[cnt].begin(), path[cnt].end());
cnt++;
}
for(int i = head[u]; i; i = e[i].nxt){
int v = e[i].to;
if(v==fa[u]) continue;
dfs(v, sum+val[v]);
}
}
int main(){
scanf("%d%d%d", &n, &m, &s);
for(int i = 0; i <= n-1; i++) scanf("%d", &val[i]);
fa[0] = -1;
while(m--){
int u, v, k;
scanf("%d%d", &u, &k);
while(k--){
scanf("%d%", &v);
add(u, v), fa[v] = u;
}
}
dfs(0, val[0]);
sort(path, path+cnt);
for(int i = cnt-1; i >= 0; i--) {
int len = path[i].size();
for(int j = 0; j < len; j++)
cout << path[i][j] << (j==len-1 ? "" : " ");
cout << endl;
}
}

Reference:

https://www.cnblogs.com/vranger/p/3502885.html

1079 Total Sales of Supply Chain (25 分)

树的遍历,不过需要特别注意每次利润点是r%而不是r

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define ll long long
using namespace std;
const int maxn = 1e5+100;
int n;
ll num[maxn];
double p, r, ans;
int head[maxn], t;
struct node{
int to, nxt;
}e[maxn];
void add(int u, int v){
e[++t] = {v, head[u]};
head[u] = t;
}
void dfs(int u, double pri){
if(head[u]==0) ans += pri*num[u];
for(int i = head[u]; i; i = e[i].nxt){
int v = e[i].to;
dfs(v, pri*(1+r*0.01));
}
}
int main(){
scanf("%d%lf%lf", &n, &p, &r);
for(int u = 0; u < n; u++){
int m, v;
scanf("%d", &m);
if(m==0) scanf("%lld", &num[u]);
while(m--){
scanf("%d", &v);
add(u, v);
}
}
dfs(0, p);
printf("%.1lf", ans);
}

1090 Highest Price in Supply Chain (25 分)

树的遍历,应当仔细审题,要求拥有最大销售价格的零售商数目,而不是编号

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define ll long long
using namespace std;
const int maxn = 1e5+100;
int n, s;
ll cnt, num[maxn];
double p, r, ans;
int head[maxn], t;
struct node{
int to, nxt;
}e[maxn];
void add(int u, int v){
e[++t] = {v, head[u]};
head[u] = t;
}
void dfs(int u, double pri){
if(head[u]==0) {
if(ans==pri) cnt++;
else if(ans<pri) ans = pri, cnt = 1;
}
for(int i = head[u]; i; i = e[i].nxt){
int v = e[i].to;
dfs(v, pri*(1+r*0.01));
}
}
int main(){
scanf("%d%lf%lf", &n, &p, &r);
for(int u = 0; u < n; u++){
int m, v;
scanf("%d", &v);
if(v==-1) s = u;
else add(v, u); }
dfs(s, p);
printf("%.2lf %d", ans, cnt);
}

1106 Lowest Price in Supply Chain (25 分)

树的遍历,和前两题是一个系列的,代码稍作修改即可

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 1e5+100;
int n, s, cnt;
ll num[maxn];
double p, r, ans = 1e10+100;
int head[maxn], t;
struct node{
int to, nxt;
}e[maxn];
void add(int u, int v){
e[++t] = {v, head[u]};
head[u] = t;
}
void dfs(int u, double pri){
if(head[u]==0) {
if(ans==pri) cnt++;
else if(ans>pri) ans = pri, cnt = 1;
}
for(int i = head[u]; i; i = e[i].nxt){
int v = e[i].to;
dfs(v, pri*(1+r*0.01));
}
}
int main(){
scanf("%d%lf%lf", &n, &p, &r);
for(int u = 0; u < n; u++){
int m, v;
scanf("%d", &m);
while(m--){
scanf("%d", &v);
add(u, v);
}
}
dfs(0, p);
printf("%.4lf %d", ans, cnt);
}

1094 The Largest Generation (25 分)

树的遍历,简直是个大水题

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 1e5+100;
int n, m;
int resLev, maxLev, res, cnt[maxn];
int head[maxn], t;
struct node{
int to, nxt;
}e[maxn];
void add(int u, int v){
e[++t] = {v, head[u]};
head[u] = t;
}
void dfs(int u, int lev){
cnt[lev]++, maxLev = max(maxLev, lev);
for(int i = head[u]; i; i = e[i].nxt){
int v = e[i].to;
dfs(v, lev+1);
}
}
int main(){
scanf("%d%d", &n, &m);
while(m--){
int u, v, num;
scanf("%2d %d", &u, &num);
while(num--){
scanf("%d", &v);
add(u, v);
}
}
dfs(1, 1);
for(int i = 1; i <= maxLev; i++)
if(res<cnt[i]) resLev = i, res = cnt[i];
printf("%d %d", res, resLev);
}

2.二叉查找树

1043 Is It a Binary Search Tree (25 分)

一种方法是用给出的输入构造出一棵二叉搜索树,然后再对这棵树进行前序遍历,判断得到的结果是否和输入一致,如果不一致,那就输出 NO,如果一致就输出这这棵树的后序遍历结果。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#define ll long long
#define inf 0x3f3f3f3f
#define pb push_back
using namespace std;
const int maxn = 1e5+100;
int n, data;
vector<int> orgin, pre, preMir, post, postMir;
struct node{
int data;
node *lch, *rch;
};
//构建BST,需要加&
void insert(node* &root, int data){
if(root==NULL){
root = new node;
root->data = data;
root->lch = root->rch = NULL;
return;
}
if(data<root->data) insert(root->lch, data);
else insert(root->rch, data);
}
void preOrder(node *root){
if(root!=NULL){
pre.pb(root->data);
// printf("%d ", root->data);
preOrder(root->lch);
preOrder(root->rch);
}
}
void preMirOrder(node *root){
if(root!=NULL){
preMir.pb(root->data);
preMirOrder(root->rch);
preMirOrder(root->lch);
}
}
void postOrder(node *root){
if(root!=NULL){
postOrder(root->lch);
postOrder(root->rch);
post.pb(root->data);
}
}
void postMirOrder(node *root){
if(root!=NULL){
postMirOrder(root->rch);
postMirOrder(root->lch);
postMir.pb(root->data);
}
}
void test(){
for(int i = 0; orgin[i]; i++) {
printf("%d", orgin[i]);
if(i!=orgin.size()-1) printf(" ");
else printf("\n");
}
for(int i = 0; pre[i]; i++) {
printf("%d", pre[i]);
if(i!=pre.size()-1) printf(" ");
else printf("\n");
}
}
int main(){
scanf("%d", &n);
node *root = NULL;
while(n--){
scanf("%d", &data);
orgin.pb(data);
insert(root, data);
}
preOrder(root);
preMirOrder(root);
// test();
if(orgin==pre){
printf("YES\n");
postOrder(root);
int len = post.size();
for(int i = 0; i < len; i++) {
printf("%d", post[i]);
if(i!=len-1) printf(" ");
}
}
else if(orgin==preMir){
printf("YES\n");
postMirOrder(root);
int len = postMir.size();
for(int i = 0; i < len; i++) {
printf("%d", postMir[i]);
if(i!=len-1) printf(" ");
}
}
else printf("NO\n"); }

Method 1

另一种方法是假设这个输入序列是对的,然后利用这个输入序列去得到后序序列并保存,如果最终得到的结果中节点个数不够(这种情况下部分节点不会被遍历到,e.g 8 6 8 5 10 9 11),那说明它不是正确的前序遍历,否则就直接输出得到的结果。这种方法基于以下前提:

一般情况下,我们要根据一棵二叉树的前序遍历结果和中序遍历结果才能得到它的后序遍历结果。但由于这里是BST,因此根据左子树所有节点的键值小于根节点这个特点就可以划分左右子树进行遍历,从而得出后序遍历结果

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#define ll long long
#define inf 0x3f3f3f3f
#define pb push_back
using namespace std;
const int maxn = 1e5+100;
int n;
bool isMirror;
vector<int> pre, post;
void getpost(int root, int tail){
if(root>tail) return;
int i = root + 1, j = tail;
if(isMirror){
while(i<=tail&&pre[i]<pre[root]) i++;
while(j>=root+1&&pre[j]>=pre[root]) j--;
}
else{
while(i<=tail&&pre[i]>=pre[root]) i++;
while(j>=root+1&&pre[j]<pre[root]) j--;
}
getpost(root+1, j);
getpost(i, tail);
post.pb(pre[root]);
}
int main(){
scanf("%d", &n);
pre.resize(n);//使用vector输入数据要预先分配内存
for(int i = 0; i <= n-1; i++) scanf("%d", &pre[i]);
getpost(0, n-1);
if(post.size()!=n){
isMirror = true, post.clear();
getpost(0, n-1);
}
if(post.size()==n){
printf("YES\n%d", post[0]);
for(int i = 1; i <= n-1; i++)
printf(" %d", post[i]);
}
else printf("NO\n"); }

Method 2

Reference:

树的前序、中序、后续遍历(以根节点的访问顺序为界定):

https://www.cnblogs.com/wizarderror/p/10816635.html

如何唯一确定一棵二叉树&&先序遍历和后序遍历为什么不能唯一地确定一棵二叉树?(最简单的办法:反证法)

https://www.zybang.com/question/fc1b72ae09eadcb6b95ffbf2e675e432.html

https://www.nowcoder.com/questionTerminal/e77e06b71aa548ed8aefd030edb9b4a2

https://blog.csdn.net/chaoyue1216/article/details/7609689

https://zhuanlan.zhihu.com/p/73438175(见评论)

题解:

https://www.cnblogs.com/codervivi/p/13126320.html(推荐)

https://blog.csdn.net/qq_41528502/article/details/104389771

https://www.liuchuo.net/archives/2153

1099 Build A Binary Search Tree (30 分)

BST的中序遍历我们可以通过排序来得到,由此遍历二叉树时加上节点所在层数的信息,我们就能得出层次遍历的序列,最后输出即可

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#define ll long long
#define inf 0x3f3f3f3f
#define pb push_back
using namespace std;
const int maxn = 1e5+100;
int n, t, val[105], maxDepth;
vector<int> g[105], lev[105];
void dfs(int u, int dep){
if(u==-1) return;
maxDepth = max(maxDepth, dep);
dfs(g[u][0], dep+1);
lev[dep].pb(val[t++]);
dfs(g[u][1], dep+1);
}
int main(){
scanf("%d", &n);
for(int i = 0; i <= n-1; i++){
int u, v;
scanf("%d%d", &u, &v);
g[i].pb(u), g[i].pb(v);
}
for(int i = 0; i <= n-1; i++) scanf("%d", &val[i]);
sort(val, val+n), dfs(0, 0);
for(int i = 0; i <= maxDepth; i++){
for(int j = 0; j < lev[i].size(); j++){
printf("%d", lev[i][j]);
if(i==maxDepth&&j==lev[i].size()-1) continue;
else printf(" ");
} }
}

1064 Complete Binary Search Tree (30 分)

1099的完全二叉树版本。使用数组来存放完全二叉树,对于某一结点u, 其左右孩子的编号分别为2*u和2*u+1(根节点为1),观察易发现数组会按照层序来存放完全二叉树的n个节点。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#define ll long long
#define inf 0x3f3f3f3f
#define pb push_back
using namespace std;
const int maxn = 1e5+100;
int n, t, val[1005], tree[1005];
void dfs(int u, int dep){
if(u>n) return;
dfs(2*u, dep+1);
tree[u] = val[++t];
dfs(2*u+1, dep+1);
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &val[i]);
sort(val+1, val+1+n), dfs(1, 0);
printf("%d", tree[1]);
for(int i = 2; i <= n; i++) printf(" %d", tree[i]);
}

3.二叉树的遍历

1020 Tree Traversals (25 分)

利用后序遍历和中序遍历来构建二叉树,按照两种序列的特性递归划分子树,由此来确定节点即可

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#define ll long long
#define inf 0x3f3f3f3f
#define pb push_back
using namespace std;
const int maxn = 1e5+100;
int n, post[maxn], in[maxn], maxDep;
vector<int> lev[maxn];
void dfs(int l1, int r1, int l2, int r2, int dep){
if(l1>r1||l2>r2) return;
int now = l2, dis;
for(int i = l2; i <= r2; i++)
if(in[i]==post[r1]) now = i;
lev[dep].pb(in[now]), maxDep = max(maxDep, dep);
dis = now-l2;
dfs(l1, l1+dis-1, l2, l2+dis-1, dep+1);
dfs(l1+dis, r1-1, l2+dis+1, r2, dep+1);
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &post[i]);
for(int i = 1; i <= n; i++) scanf("%d", &in[i]);
dfs(1, n, 1, n, 0);
for(int i = 0; i <= maxDep; i++)
for(int j = 0; j < lev[i].size(); j++){
printf("%d", lev[i][j]);
if(i==maxDep&&j==lev[i].size()-1) continue;
else printf(" ");
} }

1086 Tree Traversals Again (25 分)

首先要明确一点:先序、中序和后序遍历过程,其经过节点的路线一样,只是访问节点的时机不一样

这里Push的次序我们可以看作是先序遍历,Pop按照题意为中序遍历,于是问题就转化成了如何由先序遍历和中序遍历求后续遍历

最后注意处理输入即可

#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <vector>
#define ll long long
#define inf 0x3f3f3f3f
#define pb push_back
using namespace std;
const int maxn = 1e5+100;
int n, val;
int pre[maxn], t1, in[maxn], t2, post[maxn], t3;
int t, sta[maxn];
string str;
void dfs(int l1, int r1, int l2, int r2){
if(l1>r1) return;
int now = l2, dis;
for(int i = l2; i <= r2; i++)
if(in[i]==pre[l1]) now = i;
dis = now-l2;
dfs(l1+1, l1+1+dis-1, l2, l2+dis-1);
dfs(l1+1+dis, r1, l2+dis+1, r2);
post[++t3] = in[now];
}
int main(){
scanf("%d", &n);
int time = 2*n;
while(time--){
cin >> str;
if(str=="Push"){
scanf("%d", &val);
pre[++t1] = sta[++t] = val;
}
else in[++t2] = sta[t--];
}
dfs(1, n, 1, n);
printf("%d", post[1]);
for(int i = 2; i <= t3; i++) printf(" %d", post[i]);
}

1102 Invert a Binary Tree (25 分)

An inversion, or mirror, of a Binary Tree (T),​ is just a Binary Tree M(T) whose left and right children (of all non-leaf nodes) are swapped.

按题目要求模拟即可,注意题目中名词的概念和数据输入

#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <vector>
#define ll long long
#define inf 0x3f3f3f3f
#define pb push_back
using namespace std;
const int maxn = 1e5+100;
int n, maxDep;
int in[maxn], t;
vector<int> g[maxn], lev[maxn];
bool vis[maxn];
void dfs(int u, int dep){
if(u==-1) return;
dfs(g[u][0], dep+1);
in[++t] = u;
lev[dep].pb(u), maxDep = max(maxDep, dep);
dfs(g[u][1], dep+1);
}
int main(){
scanf("%d", &n);
for(int i = 0; i <= n-1; i++){
char u, v;
scanf(" %c %c", &u, &v);
v=='-' ? g[i].pb(-1) : g[i].pb(v-'0'), vis[v-'0'] = 1;
u=='-' ? g[i].pb(-1) : g[i].pb(u-'0'), vis[u-'0'] = 1;
}
for(int i = 0; i <= n-1; i++)
if(!vis[i]) dfs(i, 1);
for(int i = 1; i <= maxDep; i++)
for(int j = 0; j < lev[i].size(); j++){
printf("%d", lev[i][j]);
if(i==maxDep&&j==lev[i].size()-1) continue;
else printf(" ");
}
printf("\n%d", in[1]);
for(int i = 2; i <= n; i++) printf(" %d", in[i]);
}

4.平衡二叉树

1066. Root of AVL Tree (25)

泛泛的了解了下AVL树,看了慕课上视频和一些Wiki资料、博客啥的,当然还有些Splay、Treap、红黑树等等。目前不打算深入,一是没有对应的应用场景去驱动;二是要是以考证为目的来说,这些知识点有点小复杂,掌握需要花费过多的时间和精力而PAT不常考。

对AVL树的旋转操作感性理解就是:要使树达到平衡,其左右子树大小分布要尽可能的均匀,由于是二叉搜索树所以让中位数或者其附近的数作为根节点是个不错的选择。当其平衡性遭到破坏的时候,通过选取更合理的根节点来达到重新平衡的目的,旋转操作就是用尽可能简单的方法达到这个效果,四种不同的旋转操作只是对节点插入的位置做了分类讨论而已。

这道题目直接套用AVL树基本操作的模板即可

#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <vector>
#define ll long long
#define inf 0x3f3f3f3f
#define pb push_back
using namespace std;
const int maxn = 1e5+100;
int n, val;
struct node{
int val;
node *lch, *rch;
};
int getHeight(node* root){
if(root==NULL) return 0;
return max(getHeight(root->lch), getHeight(root->rch))+1;
}
node* rotateLeft(node* root){
node* now = root->rch;
root->rch = now->lch;
now->lch = root;
return now;
}
node* rotateRight(node* root){
node* now = root->lch;
root->lch = now->rch;
now->rch = root;
return now;
}
node* rotateLeftRight(node* root){
root->lch = rotateLeft(root->lch);
return rotateRight(root);
}
node* rotateRightLeft(node* root){
root->rch = rotateRight(root->rch);
return rotateLeft(root);
}
void insert(node* &root, int val){
if(root==NULL){
root = new node;
root->val = val;
root->lch = root->rch = NULL;
return;
}
if(val<root->val){
insert(root->lch, val);
if(getHeight(root->lch)-getHeight(root->rch)==2)
root = val < root->lch->val ? rotateRight(root) : rotateLeftRight(root);
}
else{
insert(root->rch, val);
if(getHeight(root->lch)-getHeight(root->rch)==-2)
root = val >= root->rch->val ? rotateLeft(root) : rotateRightLeft(root);
}
}
int main(){
scanf("%d", &n);
node* root = NULL;
while(n--){
scanf("%d", &val);
insert(root, val);
}
printf("%d", root->val);
}

Reference:

AVL树:

https://www.icourse163.org/learn/ZJU-93001?tid=1003997005#/learn/content?type=detail&id=1007588489&cid=1009165001(其中思想讲的很好)

https://blog.csdn.net/qq_25343557/article/details/89110319

https://en.wikipedia.org/wiki/AVL_tree

https://www.tutorialspoint.com/data_structures_algorithms/avl_tree_algorithm.htm

题解:

https://www.liuchuo.net/archives/2178(柳婼确实写的很不错)

5.堆

1098 Insertion or Heap Sort (25 分)

这题主要考察的是堆这种数据结构,又去把浙大数据结构的慕课看了看,解出此题需要掌握堆的概念及其各种操作,还有排序相关知识

此外,最后提交的时候测试样例2段错误

对于插入排序的下一次迭代的位置,得从前往后找,不能从后往前找
否则测试样例2错误。
例如:
4
3 4 2 1
3 4 2 1
-----------
正确答案:
Insertion Sort
2 3 4 1

#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <vector>
#define ll long long
#define inf 0x3f3f3f3f
#define pb push_back
using namespace std;
const int maxn = 1e5+100;
int n, a[maxn], b[maxn];
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
for(int i = 1; i <= n; i++) scanf("%d", &b[i]);
if(b[1]<=b[2]){
printf("Insertion Sort\n");
// int p = n;
// while(a[p]==b[p]) p--;
int p = 1;
while(b[p+1]>=b[p]) p++;
sort(b+1, b+1+p+1);
}
else{
printf("Heap Sort\n");
int p = n, par, child, tmp;
while(b[p]>=b[0]&&b[p-1]<=b[p]) p--;
swap(b[1], b[p--]), tmp = b[1];
for(par = 1; par*2 <= p; par = child){
child = par*2;
if(child!=p&&b[child]<b[child+1]) child++;
if(tmp>=b[child]) break;
else b[par] = b[child];
}
b[par] = tmp;
}
printf("%d", b[1]);
for(int i = 2; i <= n; i++) printf(" %d", b[i]);
}

Reference:

堆&排序:

https://www.icourse163.org/learn/ZJU-93001?tid=1003997005#/learn/content?type=detail&id=1007588492&cid=1009165016

https://www.icourse163.org/learn/ZJU-93001?tid=1003997005#/learn/content?type=detail&id=1007588512&cid=1009165136&replay=true

Code:

借鉴mooc&&柳婼

https://blog.csdn.net/liuchuo/article/details/52252172

debug:

https://blog.csdn.net/njtechlcj/article/details/105400209

https://blog.csdn.net/ever_promise/article/details/107567183

6.并查集

1107 Social Clusters (30 分)

并查集的基本操作,需要注意读懂题目的意思:

有n个人,每个人喜欢k个活动,如果两个人有任一活动相同,就认为他们处于同一个社交网络。求这n个人一共形成了多少个社交网络

#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <vector>
#define ll long long
#define inf 0x3f3f3f3f
#define pb push_back
using namespace std;
const int maxn = 1e4+100;
int n, m, h, tot, f[maxn], cnt[maxn];
int t, hobby[maxn];
bool vis[maxn];
vector<int> g[maxn];
int find(int x){
if(f[x]!=x) f[x] = find(f[x]);
return f[x];
}
void merge(int x, int y){
x = find(x), y = find(y);
f[x] = y;
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++){
f[i] = i;
scanf("%d:", &m);
while(m--){
scanf("%d", &h);
g[h].pb(i);
if(!vis[h]) hobby[++t] = h, vis[h] = 1;
}
}
for(int i = 1; i <= t; i++){
h = hobby[i];
for(int j = 1; j < g[h].size(); j++){
if(find(g[h][0])!=find(g[h][j])) merge(g[h][0], g[h][j]);
}
}
for(int i = 1; i <= n; i++) cnt[find(i)]++;
for(int i = 1; i <= n; i++)
if(cnt[i]!=0) tot++;
sort(cnt+1, cnt+1+n);
printf("%d\n%d", tot, cnt[n]);
for(int i = n-1; i >= n-tot+1; i--) printf(" %d", cnt[i]);
}

PTA甲级—树的更多相关文章

  1. PTA甲级1094 The Largest Generation (25分)

    PTA甲级1094 The Largest Generation (25分) A family hierarchy is usually presented by a pedigree tree wh ...

  2. PTA 7-3 树的遍历 (25分)

    PTA 7-3 树的遍历 (25分) 给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列.这里假设键值都是互不相等的正整数. 输入格式: 输入第一行给出一个正整数N(≤30),是二叉树中结点 ...

  3. PTA 03-树1 树的同构 (25分)

    题目地址 https://pta.patest.cn/pta/test/15/exam/4/question/711 5-3 树的同构   (25分) 给定两棵树T1和T2.如果T1可以通过若干次左右 ...

  4. PTA L2-006 树的遍历-二叉树的后序遍历+中序遍历,输出层序遍历 团体程序设计天梯赛-练习集

    L2-006 树的遍历(25 分)   给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列.这里假设键值都是互不相等的正整数. 输入格式: 输入第一行给出一个正整数N(≤),是二叉树中结点的 ...

  5. PAT甲级 树 相关题_C++题解

    树 目录 <算法笔记>重点摘要 1004 Counting Leaves (30) 1053 Path of Equal Weight (30) 1079 Total Sales of S ...

  6. PTA 7-10 树的遍历(二叉树基础、层序遍历、STL初体验之queue)

    7-10 树的遍历(25 分) 给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列.这里假设键值都是互不相等的正整数. 输入格式: 输入第一行给出一个正整数N(≤30),是二叉树中结点的个数 ...

  7. PTA甲级B1061 Dating

    目录 B1061 Dating (20分) 题目原文 Input Specification: Output Specification: Sample Input: Sample Output: 生 ...

  8. [刷题] PTA 03-树1 树的同构

    程序: 1 #include <stdio.h> 2 #define MaxTree 10 3 #define ElementType char 4 #define Tree int 5 ...

  9. PTA 甲级 1139

    https://pintia.cn/problem-sets/994805342720868352/problems/994805344776077312 其实这道题目不难,但是有很多坑点! 首先数据 ...

  10. PAT 甲级 树专题小结

    1.已知两个序链表建树 先序中序建树 PAT 1086 node *buildTree(vector<int>pre,vector<int>in,int pl,int pr,i ...

随机推荐

  1. 手动设置提示在此环境中不可导入Django

    手动设置提示在此环境中不可导入Django 环境参数添加manage.py中的代码'DJANGO_SETTINGS_MODULE', 'codeProject.settings'

  2. [oeasy]python0082_[趣味拓展]控制序列_清屏_控制输出位置_2J

    光标位置 回忆上次内容 上次了解了键盘演化的过程 ESC 从 组合键 到 独立按键   ​   添加图片注释,不超过 140 字(可选)   ESC的作用 是 进入 控制序列 配置 控制信息 控制信息 ...

  3. C#:只支持GET和POST方法的浏览器,如何发送PUT/DELETE请求?RESTful WebAPI如何响应?

    理想的RESTful WebAPI采用面向资源的架构,并使用请求的HTTP方法表示针对目标资源的操作类型.但是理想和现实是有距离的,虽然HTTP协议提供了一系列原生的HTTP方法,但是在具体的网络环境 ...

  4. 🚀RabbitMQ+redis+Redisson分布式锁+seata实现订单服务

    引言 订单服务涉及许多方面,分布式事务,分布式锁,例如订单超时未支付要取消订单,订单如何防止重复提交,如何防止超卖.这里都会使用到. 开启分布式事务可以保证跨多个服务的数据操作的一致性和完整性, 使用 ...

  5. 在MySQL中 Truncate Delect Drop 的区别

    在MySQL中 Truncate Delect Drop 的区别 面试问题: -- -- 请详细描述MySQL中TRUNCATE TABLE.DELETE FROM和DROP TABLE三个命令的区别 ...

  6. CCF 无线网络

    题目原文 问题描述(题目链接登陆账号有问题,要从这个链接登陆,然后点击"模拟考试",进去找本题目) 试题编号: 201403-4 试题名称: 无线网络 时间限制: 1.0s 内存限 ...

  7. OpenStack 基本命令

    keystone source /etc/keystone/admin-openrc.sh #登录 openstack user create --password ps1234 --email hq ...

  8. 【vue3】详解单向数据流,大家千万不用为了某某而某某了。

    总览 Vue3 的单向数据流 尽信官网,不如那啥. vue的版本一直在不断更新,内部实现方式也是不断的优化,官网也在不断更新. 既然一切皆在不停地发展,那么我们呢?等着官网更新还是有自己的思考? 我觉 ...

  9. 【Java】自制查找工具

    需求:查找后台代码中写的SQL是否包含拆分表,如果存在,则返回那些表名 Context.txt 粘贴我们找到的DAO层代码,因为所有方法封装的SQL都在DAO层里[就理解为筛查的字符串] Dictio ...

  10. 运维 + AI,你得先搞懂这些

    很感谢夜莺提供如此优质的平台能和行业内顶尖技术大佬做面对面的交流,在这个会议中又学习到了很多有趣有深度的内容,给我在未来探索的道路上提供了一些新的指引方向.同时感谢夜莺社区的邀请,在此再做一次关于AI ...