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使用 DoesNotExist 异常和 Logger 来记录异常情况

    代码不仅处理了特定的异常类型,还可以添加更多的调试信息来帮助诊断问题.可以使用 DoesNotExist 异常和 Logger 来记录异常情况. from django.core.exceptions ...

  2. [oeasy]python024_vim读取文件_从头复制到尾_撤销_重做_reg_寄存器

    Guido的简历 回忆上次内容 python 是Guido制作的语言 从Guido刚入职场 就开始的项目 python这个项目 一直跟随Guido   Guido 曾经在 cwi cnri beope ...

  3. oeasy 教您玩转linux 010303文件管理器 nautilus

    我们来回顾一下 上一部分我们都讲了什么? 讲了火狐 火狐的位置 用命令行打开多个网址 火狐的升级 火狐桌面建立快捷方式 我们可以知道桌面快捷方式文件的名称么? 从文件管理器到命令行 按住文件 拖动到t ...

  4. CF479C 题解

    洛谷链接&CF 链接 题目简述 一个人想要安排期末考试的时间. 有 \(n\) 场考试,每场考试有两个时间 \(x_i,y_i\),一个是老师规定的时间,另外一个是他与老师商量好的考试时间. ...

  5. vue项目使用elementUI的el-upload组件实现图片上传和文件上传的公共组件封装

    图片上传: <template> <div class="upload-pic"> <el-upload class="upload-dem ...

  6. AppiumDesktop控制手机和安卓模拟器

    前言: 本期内容 如何用AppiumDesktop连接安卓手机和安卓模拟器 AppiumDesktop基本参数的获取方法,及如何驱动安卓设备 AppiumDesktop在模拟登陆和爬虫中用到的基本功能 ...

  7. 【ElasticSearch】突破深度分页限制的分页方案

    一.场景需求 最近在忙一个新的项目,数据源是ES,但是功能就是对文档进行翻页查询 ES提供了分页查询,就是from + size深度查找,但是使用有限制,只能在1万条内 我和同事的意见是1万条之后的数 ...

  8. FFmpeg在游戏视频录制中的应用:画质与文件大小的综合比较

    我们游戏内的视频录制目前只支持avi固定码率,在玩家见面会上有玩家反馈希望改善录制画质,我最近在研究了有关视频画质的一些内容并做了一些统计. 录制视频大小对比 首先在游戏引擎中增加了对录制mp4格式的 ...

  9. 连接huggingface.co报错:(MaxRetryError("SOCKSHTTPSConnectionPool(host='huggingface.co', port=443) (SSLEOFError(8, '[SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol (_ssl.c:1007)

    参考: https://blog.csdn.net/shizheng_Li/article/details/132942548 https://blog.csdn.net/weixin_4220944 ...

  10. [COCI 2023/2024 #3] Slučajna Cesta 题解

    前言 期望套期望,很有意思.来一发考场首 A,近 \(\Theta(n)\) 的算法. 题目链接:洛谷. 题意简述 一棵树,每条边随机设有方向.对于所有 \(i\),从 \(i\) 开始随机游走,直到 ...