马蹄集 oj赛(双周赛第二十九次)

目录

供水管线

附庸的附庸

逆序

队列安排

管理通讯簿

调整队伍

泡泡

一元多项式的加法

约瑟夫环

暧昧团

快排变形

采蜜


供水管线

难度:钻石● 时间限制:1秒巴: 占用内存:128 M

在几个城市之间原本要规划修建许多条下水管道,管理人员发现这些管道会形成一条回路,而下水道只要将城市联通即可,所以回路会加大施工的成本。所以希望你来帮忙找出多余的管道来进行优化。当然管道和管道之间是有区别的,比如用s来表示i到j的管道管理费用,8越小则表示该管道管理费用越低。能否去除一些管线,使得总管理成本最低。求出最低的管理成本(不存在自身与自身成为回路的管道)。

python 复制代码
def main():
    #code here
    n,k = map(int,input().split())
    # 这里我采用的是字典和元组存储顶点和边长,格式为为{(1,2):5,(1,2):3.....}
    # 另外也可以使用类进行实现,但是我感觉会有些麻烦。不过思想都是统一的,喜欢使用那个就使用那个
    dic = {}
    # 记录输入的数据
    for i in range(k):
        i,j,c = map(int,input().split())
        if (i,j) in dic:
            if dic[(i,j)] > c:
                 dic[(i,j)] = c
        else:
            dic[(i,j)] = c
    # 排序,按照边的长度从小到大排序
    new_dic = dict(sorted(dic.items(),key=lambda x:x[1]))
    reslut = 0
    #为每个顶点配置一个不同的标记,
    assists = [i for i in range(n)]
    for key,item in new_dic.items():
        #找到当前边的两个顶点在 assists 数组中的位置下标
        initial = key[0] -1
        end = key[1]-1
        num = 0  # 记录选择边的数量
        # 如果顶点位置存在且顶点的标记不同,说明不在一个集合中,不会产生回路
        if assists[initial] != assists[end]:
            # 记录该边,作为最小生成树的组成部分,其实就是记录顶点和边,具体情况根据实际情况可以自己调整
            # 在本题中题目只需要记录最低管理费用,所以只需要记录每次添加进的数据
            reslut+=item
            #将新加入生成树的顶点标记全部改为一样的  关键内容
            elem = assists[end]
            num+=1
            for j in range(n):
                if assists[j] == elem:
                    assists[j]= assists[initial]
                
            #如果选择的边的数量和顶点数相差1,证明最小生成树已经形成,退出循环
            if num == n-1:
                break


    print(reslut)



if __name__ == '__main__':
    main();

附庸的附庸

了难度:黄金时间限制:1秒巴 占用内存:128 M

蒙德城的旧贵族们存在着附庸的关系。欧洲有一位伟人说过,我的附庸的附庸不是我的附庸。尽管如此他们还是存在着隐性的自上而下的关系,属于同一个利益集团。所以,在蒙德城,附庸的附庸也是附庸。也就是说,如果两个附庸都能追溯到同一个贵族,他们也存在附庸关系(仅仅是蒙德人这样认为)蒙德城人口众多,现在小码哥把各人的关系都梳理了出来交给了你,并想让你告诉他,某两个人存不存在附庸关系(按照蒙德人的观念)。

格式

输入格式:第一行一个整数 n,表示几个关系;

接下来 n 行,每行两个数 a,b,表示b是 a 的附庸;下一行一个整数 q,表示询问次数;

接下来 q 行,每行两个数 a,b,询问 a和b是否存在附庸关系

输出格式:q 行,每行一个数。

1表示存在附庸关系,0表示不存在。

python 复制代码
n = int(input())
fa = [i for i in range(2 * 10 ** 4 + 7)]
def find(x):
    if x == fa[x]:
        return x
    fa[x] = find(fa[x])
    return fa[x]
for _ in range(n):
    a, b = map(int, input().split())
    fa[find(b)] = find(a)
q = int(input())
for _ in range(q):
    a, b = map(int, input().split())
    if find(a) == find(b):
        print(1)
    else:
        print(0)

逆序

少 难度:钻石时间限制:1秒巴 占用内存:128 M

给一个长度为n的排列p,找一个元素,使得从排列中取出这个元素以后排列的records最多。record 是一个元素 ai满足:对于每个正整数 1≤j<i,ai>aj。一个

格式

输入格式:第一行为 n;

第二行为排列 p。

输出格式:一个整数即答案。

样例 1

输入:5

复制

5 123 4

输出:5

复制

cpp 复制代码
//
// Created by felix on 2024/6/27.
//
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 +7;
int n;
int c[N],chg [N];

int lowbit(int x){ return x &-x; }
void add(int x) {
    for (;x < N;x += lowbit(x))
        c[x]++;
}
        int sum(int x) {
    int ret =0;
    for (;x>0;x-=lowbit(x))
        ret += c[x];
    return ret;
}
        int main(){
            cin >>n;
            int x=0,maxx =0;
            for (int i = 1;i<=n;i++){
                cin >>x;
                maxx = max(maxx,x);
                int cnt = sum(x);
                if (cnt ==i-1)
                    chg [maxx]--;
                else if(cnt==i-2)
                chg [maxx]++;
                add (x);
            }
    int ans = 1;
    for (int i = 1;i <= n;i++)
        if (chg[i] > chg[ans])
            ans = i;
    cout <<ans <<endl;
    return 0;
}

队列安排

巴 占用内存:128 M了 难度:黄金时间限制:1秒

-个学校里老师要将班上N个同学排成一列,同学被编号为1~N,他采取如下的方法:1.先将1号同学安排进队列,这时队列中只有他一个人;2.2-N号同学依次入列,编号为i的同学入列方式为:老师指定编号为i的同学站在编号为1~(-1)中某位同学(即之前已经入列的同学)的左边或右边;3.从队列中去掉M(M<N)个同学,其他同学位置顺序不变

在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号。

格式

输入格式:第1行为一个正整数 N ,表示了有 N 个同学;第 2-N 行,第i行包含两个整数k,p,其中k为小于i的正整数,p为0或者1。若p为0,则表示将i号同学插入到 k号同学的左边,p为1则表示插入到右边;第 N +1 行为一个正整数 M ,表示去掉的同学数目;接下来 M 行,每行一个正整数...,表示将:号同学从队列中移去,如果"号同学已经不在队列中则忽略这一条指令。

python 复制代码
n = int(input())
head = 1
pre = [0] * 100005
nxt = [0] * 100005
exist = [0] * 100005

for i in range(2, n + 1):
    k, p = map(int, input().split())

    if not p:
        if k == head:
            head = i
        pre[i] = pre[k]
        nxt[i] = k
        nxt[pre[k]] = i
        pre[k] = i

    if p:
        pre[i] = k
        nxt[i] = nxt[k]
        pre[nxt[k]] = i
        nxt[k] = i

m = int(input())

for i in range(1, m + 1):
    x = int(input())
    if x == head:
        head = nxt[x]
    if exist[x]:
        continue

    nxt[pre[x]] = nxt[x]
    pre[nxt[x]] = pre[x]
    exist[x] = 1

i = head
while i:
    print(i, end=" ")
    i = nxt[i]

管理通讯簿

四 占用内存:128 M难度:白银时间限制:1秒

已知一个通讯记录是由学号(6位整数,并且学号不重复)、姓名(长度小于18,只包含大写字母和小写字母)、性别(F或M)、出生日期(长度小于18)、邮编(6位整数)、通讯地址(长度小于38,只包含大写字母或小写字母)、QQ号(9位整数)、电话(11位整数)等数据项组成,利用单链表编写管理通讯(多个通讯记录)的程序,要求实现添加、删除、查找、逆序打印通讯记录功能。输入必须合理

格式

输入格式:第一行输入学生数量,正整数(大于2,小于10);后续行依次输入每个学生学号、姓名、性别、生日、邮编、通讯地址、QQ号、电话,空格分隔。每个学生一行。输入数据必须合理,不考虑不合理的输入或是溢出等特殊情况。然后输入正整数N,根据N的值执行添加、删除、查找、逆序打印。

如上文所述,首先输入学生信息来建立通讯录。然后输入正整数N:如果N为1,执行添加操作,后续行输入一个学生学号、姓名、性别、生日、邮编、通讯地址、QQ号、电话,空格分隔。然后输出第一行Therecords is:后续行逆序打印通讯录。

如果N为2,执行删除操作,第二行输入整型学号,删除对应节点(若找不到要删除的节点,则不进行删除操作),然后输出第一行Therecordsis:,后续行逆序打印通讯录。

cpp 复制代码
//
// Created by felix on 2024/6/27.
//
#include <bits/stdc++.h>
using namespace std;

struct NODE {
    int studentNum, postCode, qq, nex;
    char name[10], sex[10], birthDay[10], address[30], tel[11];
} node[10];

int head, pos;

void insert() {
    NODE tmp;
    cin >> tmp.studentNum >> tmp.name >> tmp.sex >> tmp.birthDay >>
        tmp.postCode >> tmp.address >> tmp.qq >> tmp.tel;
    node[++pos] = tmp;
    node[pos].nex = node[head].nex;
    node[head].nex = pos;
}

void del() {
    int num;
    cin >> num;
    int curr = head;
    while (node[curr].nex) {
        if (node[node[curr].nex].studentNum == num) {
            node[curr].nex = node[node[curr].nex].nex;
            return;
        } else {
            curr = node[curr].nex;
        }
    }
}

void find() {
    int num;
    cin >> num;
    int curr = node[head].nex;
    while (curr) {
        if (node[curr].studentNum == num) {
            cout << node[curr].studentNum << " " << node[curr].name << " "
            << node[curr].sex << " " << node[curr].birthDay << " "
            << node[curr].postCode << " " << node[curr].address << " "
            << node[curr].qq << " " << node[curr].tel << endl;
            return;
        } else {
            curr = node[curr].nex;
        }
    }
    cout << "not found";
}

void print() {
    cout << "The records is:"<< endl;
    int curr = node[head].nex;

    while (curr) {
        cout << node[curr].studentNum << " " << node[curr].name << " "
        << node[curr].sex << " " << node[curr].birthDay << " "
             << node[curr].postCode << " " << node[curr].address << " "
        << node[curr].qq << " " << node[curr].tel << endl;
        curr = node[curr].nex;
    }
}

int main() {
    int n;
    cin >> n;
    head = 0;
    pos = 0;
    node[head].nex = 0;

    for (int i = 1; i <= n; i++) {
        insert();
    }

    cin >> n;
    if (n == 1) {
        insert();
        print();
    } else if (n == 2) {
        del();
        print();
    } else if (n == 3) {
        find();
    } else if (n == 4) {
        print();
    }

    return 0;
}

调整队伍

多难度:黄金巴 占用内存:128 M时间限制:1秒

小码哥迎来了他大学的第一次军训,军训的第一个项目就是列队,每个同学在队伍中都有属于自己的编号。但在练习过程中,教官怎么看这支队伍怎么不顺眼,于是决定调整一下队伍的顺序。

为了顺便考验同学们的反应力,教官与学生们约定了一个口令,每当他说xy0,x号同学就要移动到y号同学的前面,每当他说xy1,*号同学就要移动到y号同学的后面,但学生们不想一次次慢慢移动这么麻烦,想要知道队伍最后是怎么排的然后直接排好。为了解决同学们的烦恼,小码哥立刻动手原地

写了一个程序算出了最终排序。

现在告诉你队伍从前到后的初始排序编号以及教官的口令,要你得出队伍从前往后的最终排序。已知有n个学生,编号不重复且1<编号<n。

格式

输入格式:第一行两个正整数 n,m,表示学生的数量和教官口令的数量;第二行 n 个正整数,表示学生们的初始排序;接下来 m 行,每行 3 个整数,表示教官的口令。

cpp 复制代码
//
// Created by felix on 2024/6/27.
//
#include <bits/stdc++.h>
using namespace std;

const int N = 3e5 + 7;

struct node {
    int l, r;
} stu[N];

int n, m, head, tail, curr;

int main() {
    ios::sync_with_stdio(false); // Speed up input/output
    cin.tie(0);

    cin >> n >> m;
    head = 0;
    tail = 0;
    curr = 0;
    
    // Initialize the list with the initial order
    for (int i = 0; i < n; ++i) {
        int num;
        cin >> num;
        stu[num].l = curr;
        if (i == 0) {
            head = num; // first element becomes the head
        } else {
            stu[curr].r = num;
        }
        curr = num;
    }
    tail = curr;
    stu[tail].r = 0; // last element points to 0

    // Process the commands
    while (m--) {
        int x, y, op;
        cin >> x >> y >> op;
        
        // Remove x from its current position
        int t1 = stu[x].l, t2 = stu[x].r;
        if (t1) stu[t1].r = t2;
        if (t2) stu[t2].l = t1;
        if (x == head) head = t2;
        if (x == tail) tail = t1;

        if (op == 0) { // move x to the front of y
            t1 = stu[y].l;
            stu[x].l = t1;
            stu[x].r = y;
            if (t1) stu[t1].r = x;
            stu[y].l = x;
            if (y == head) head = x;
        } else { // move x to the back of y
            t2 = stu[y].r;
            stu[x].r = t2;
            stu[x].l = y;
            if (t2) stu[t2].l = x;
            stu[y].r = x;
            if (y == tail) tail = x;
        }
    }

    // Print the result
    curr = head;
    while (curr) {
        cout << curr << " ";
        curr = stu[curr].r;
    }
    cout << endl;

    return 0;
}

泡泡

乡难度:黄金时间限制:1秒巴 占用内存:128 M

小码哥小时候喜欢吹泡泡,有一次他吹出了几个一样小的泡泡,过了一段时间后,这些泡泡相互碰到一起,形成了各种大小的泡泡...,但小码哥不知道的是,他生活的地方是母体构筑的虚拟世界,里面的泡泡实际是一串串被拼成环状的数字。

小码哥一开始吹出的泡泡被母体记为1,2,...,n,而泡泡的碰撞融合实际是数字的拼接(有序)。母体会通过模拟得知两个泡泡环碰撞的情况(用->y表示)。例如,有一个为1-2的泡泡环与3-4-5的泡泡环碰撞,碰撞的点为1->4(后一个数字接在前一个数字下面),则会形成1-4-5-3-2的泡泡环。

一开始所有泡泡环都只有一个数字,母体演算出了泡泡之后的碰撞点,现在请你输出泡泡碰撞完后的所有泡泡的情况。

格式

输入格式:第一行两个正整数 n,m,表示一开始泡泡的数量和泡泡碰撞的次数;接下来 m 行,每行两个数字 ,y,表示泡泡碰撞的两个点。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int maxn = 1000005;

int n, m;
struct B {
    int before, next;
} b[maxn];
bool book[maxn];

int main() {
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
        b[i].before = b[i].next = i;

    while(m--) {
        int x, y;
        cin >> x >> y;
        b[b[y].before].next = b[x].next;
        b[b[x].next].before = b[y].before;
        b[x].next = y;
        b[y].before = x;
    }

    for(int i = 1; i <= n; i++) {
        if(!book[i]) {
            int t = i;
            do {
                printf("%d ", t);
                book[t] = true;
                t = b[t].next;
            } while(t != i);
            printf("\n");
        }
    }
    return 0;
}

一元多项式的加法

乡难度:钻石时间限制:1秒四占用内存:128 M

小码哥给出两个一元多项式工和,请你将这两个一元多项式相加,得到新的一元多项式 工c。

如样例:

LA=1-10x6 + 2x8 + 7x14LB=-x4+10x6-3x10 + 8x14 + 4x18LC=LA+LB=1-x4+2x8-3x10 + 15x14 +4x18

格式

输入格式:第一行两个整数n和m,分别表示 LA和 L 的项数;接下来 n 行,每行输入 L的每一项的信息,两个整数分别表示该项的系数 coef和次数expn,输入保证次数递增:接下来 m 行,每行输入 Lp 的每一项的信息,两个整数分别表示该项的系数 coe,f和次数 expn ,输入保证次数递增。

输出格式:输出k行,k为工c的项数,每行输出工。的每一项的信息,两个整数分别表示该项的系数 coef和次数 expn ,输出按次数递增。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long

const int N = 2e6 + 7;

struct NODE {
    ll nex, coef, expn;
} node[N];

int n, m, head, tail, pos;
ll coefA[N], expnA[N], coefB[N], expnB[N];

void insert(int curr, ll val1, ll val2) {
    node[++pos].coef = val1;
    node[pos].expn = val2;
    node[pos].nex = node[curr].nex;
    node[curr].nex = pos;
    if (!node[pos].nex)
        tail = pos;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%lld%lld", &coefA[i], &expnA[i]);
    for (int i = 1; i <= m; i++)
        scanf("%lld%lld", &coefB[i], &expnB[i]);

    int l = 1, r = 1;
    while (l <= n && r <= m) {
        if (expnA[l] == expnB[r]) {
            insert(tail, coefA[l] + coefB[r], expnA[l]);
            l++, r++;
        } else {
            if (expnA[l] < expnB[r]) {
                insert(tail, coefA[l], expnA[l]);
                l++;
            } else {
                insert(tail, coefB[r], expnB[r]);
                r++;
            }
        }
    }
    while (l <= n) {
        insert(tail, coefA[l], expnA[l]);
        l++;
    }
    while (r <= m) {
        insert(tail, coefB[r], expnB[r]);
        r++;
    }

    // output result
    for (int i = node[head].nex; i != 0; i = node[i].nex)
        if (node[i].coef != 0)
            printf("%lld %lld\n", node[i].coef,node[i].expn);
    return 0;
}

约瑟夫环

难度:黄金 时间限制:1秒巴: 占用内存:128 M

讲一个比较有意思的故事:约瑟夫是犹太军队的一个将军,在反抗罗马的起义中,他所率领的军队被击溃,只剩下残余的部队48余人,他们都是宁死不屈的人,所以不愿投降做叛徒。一群人表决说要死,所以用一种策略来先后杀死所有人。

于是约瑟夫建议:每次由其他两人一起杀死一个人,而被杀的人的先后顺序是由抽签决定的,约瑟夫有预谋地抽到了最后一签,在杀了除了他和剩余那个人之外的最后一人,他劝服了另外一个没死的人投降了罗马

我们这个规则是这么定的:

在一间房间总共有几个人(编号1~n),最后只能有一个人活下来。

按照如下规则去杀人:

所有人围成一圈;从1号开始顺时针(1->n)报数,每次报到q的人将被杀掉,被杀掉的人将从房间内被移走。然后从被杀掉的下一个人重新报数,继续报到g,再清除,直到剩余一人。你要做的是:当你在这一群人之间时,你必须选择一个位置以使得你变成那剩余的最后一人,也就是活下来。

实现约瑟夫环首先需要判断选择的那个人是否是最后一个幸存的人,不是的话再进行约瑟夫环行动。

cpp 复制代码
//
// Created by felix on 2024/6/27.
//
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 +10;
struct NODE{
int val,nex;
}node[N];
int pos,n,q,curr;

void insert(int curr,int num) {
    node[++pos].val = num;
    node[pos].nex = node[curr].nex;
    node[curr].nex = pos;
}
    //删除操作,被删节点的前驱节点是pre
    void del(int pre){node[pre].nex = node[node[pre].nex].nex;}
        int main(){
            cin >>n >>q;
            if(q==1){
                cout << n;
                return 0;
            }
            node[0]={0,1};//定义一个头节点
            node[1]={1,1};
            pos=1;
                for (int i=2;i <= n;i++)
                    insert(pos,i);
     while (true){
        for (int k = 1;k < q;k++)
            curr = node[curr].nex;
        if (node[curr].nex == curr){
            cout << node[curr].val;
            return 0;
        }
        del(curr);
    }
    return 0;
}

暧昧团

难度:黄金®时间限制:1秒四占用内存:128 M

小码哥正在整理NPU的学生信息。现在到了关键的一步:存储cp信息。

因为众所周知情网很乱,所以可能一个人和多个人暖昧,并且不分性别,而且有可能自己和自己暖昧。

同时一对暖昧关系可能会由于大意等原因多次记录。

现在我们知道几个人,并且有m个暖昧关系。现在我们对暖昧团进行定义:一个人所有和他有直接暖昧关系以及间接暖昧关系的集合。比如1与2暖昧,2与3暖昧,3与4暖昧,5与3暖昧,6与2暖昧,那么{1,2,3,4,5,6},{2,3},{1,4,5,6}{空集合}就均属于暖昧团,其中,{1,2,3,4,5,6}就是极大暖昧团。现在小码哥告诉你一个人名的编号,让你回答与所处极大暖昧团的大小。如果一个人和谁都不暖昧,那么答案就是1

格式

输入格式:第一行一个整数 n,m(1≤n,m<1e5 ),表示人数,和暖昧关系的数量;接下来 m 行,每行两个整数 a,b(1 ≤ a,b≤n),表示 a,b之间存在暖昧关系,

cpp 复制代码
/**
	输入格式:第一行一个整数n,m ( 1 ≤n,m ≤le5),表示人数,和暧昧关系的数量;
            接下来m行,每行两个整数a,b ( 1≤a, b≤n ),表示a,b之间存在暧昧关系;
            最后一行一个整数x,表示询问x所处极大暖昧团的大小。
	输出格式:一行一个整数表示答案。
	样例1   输入:6 8
                1 2
                5 2
                3 6
                4 5
                1 4
                2 2
                3 6
                3 6
                3
			输出:2
*/         
#include<bits/stdc++.h> 

using namespace std;
const int N = 1e5 + 5;
int f[N], s[N], n, m;

//并查集的模板
int find(int x){//查找根节点
    //将键与值对比,相同返回键;不同返回值,拿值做键在做比较
    return x == f[x] ? x : (f[x] = find(f[x]));//路径压缩
}
void merge(int i, int j){//合并暧昧值
    int x = find(i);//查找根节点的暧昧值
    int y = find(j);
    if(x != y){
        f[x] = y;//将节点赋值为根节点的值
        s[y] += s[x];//根节点的值为暧昧值的总和
    }
}
int main(){
    cin >> n >> m;
    for(int i = 1; i <= n; i++){
        s[i] = 1;//暧昧值每个人都为1
        f[i] = i;//并查集初始化
    }
    while(m--){
        int a, b;
        cin >> a >> b;
        merge(a, b);
    }
    int x;
    cin >> x;
    cout << s[find(x)];//返回根节点的索引对应的最大暧昧值
    return 0;
}

快排变形

难度:黄金

时间限制:1秒巴 占用内存:128 M

有几个数,问如果通过每次交换邻项的两个数来使数组中的元素变为升序排列。

eg:98765,

变为升序:

5 67 89。

需要10次邻项交换。

格式

输入格式:第一行输入一个整数n,表示序列长度:第二行输入 n 个数。

输出格式:输出一个整数,表示最少的交换次数。

cpp 复制代码
#include<bits/stdc++.h> 

using namespace std;
#define int long long

int n, ans = 0;
int a[200010], temp[200010];

void merge_pai(int l, int r, int mid) {
    int i = l, p = l, j = mid;
    while (i < mid && j <= r) {
        if (a[i] <= a[j]) 
            temp[p++] = a[i++];
        else {
            temp[p++] = a[j++];
            ans += mid - i;
        }
    }
    while (i < mid) 
        temp[p++] = a[i++];
    while (j <= r) 
        temp[p++] = a[j++];
    p = i = l;
    while (p <= r) 
        a[i++] = temp[p++];
}

void merge_sort(int l, int r) {
    if (l < r) {
        int mid = (l + r) / 2;
        merge_sort(l, mid);
        merge_sort(mid + 1, r);
        merge_pai(l, r, mid + 1);
    }
}

signed main() {
    cin >> n;
    for (int i = 1; i <= n; i++) 
        cin >> a[i];
    merge_sort(1, n);
    cout << ans << endl;
}

采蜜

难度:黄金● 时间限制:1秒巴 占用内存:128 M

现在有 n个蜂巢,每一个蜂窝都对应了一个蜂蜜值Si。

小码哥发现:有一些蜂窝相互联结,使得他们可以共享蜂蜜值,即该蜂巢的蜂蜜值变为:它和它连接(直接连接或间接连接)的蜂巢的蜂蜜值的和。

现在小码哥想要查询一下一些蜂巢的蜂蜜值。

格式

输入格式:第一行有两个数n(蜂巢的数量)、m(操作的数量)第二行有 n 个数字(s1,·...·,8n):分别表示了每一个蜂巢的蜂蜜值。随后有 m 行:第一个数字如果是1,则后面还有两个数字 a,b,表示此次发现蜂巢 a 和 b 是相连的。第一个数字如果是 2,则后面只有一个数字 c,表示查询所有与蜂巢 c 相连的蜂巢(包括自己)的总蜂蜜值。

输出格式:对每一次的查询操作输出查询的蜂巢的蜂蜜值。

cpp 复制代码
#include <cstdio>
#define maxn 100005
using namespace std;

int n, m, a[maxn], fa[maxn];

inline int get(int x) {
    if (x == fa[x]) return x;
    return fa[x] = get(fa[x]);
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        fa[i] = i;
    }
    while (m--) {
        int f = 0;
        scanf("%d", &f);
        if (f == 1) {
            int x, y;
            scanf("%d%d", &x, &y);
            int fx = get(x), fy = get(y);
            if (fx != fy) {
                fa[fy] = fx;
                a[fx] += a[fy];
            }
        } else {
            int x;
            scanf("%d", &x);
            printf("%d\n", a[get(x)]);
        }
    }
    return 0;
}
相关推荐
安步当歌10 分钟前
【FFmpeg】avformat_find_stream_info函数
c语言·c++·ffmpeg·视频编解码·video-codec
山河清风悠31 分钟前
线程池技术实现及参数工作流程原理
java·开发语言·算法
AIWhispers32 分钟前
【C++笔记整理—第1期】
开发语言·c++·笔记
Asher Gu43 分钟前
算法导论 总结索引 | 第四部分 第十六章:贪心算法
算法·贪心算法
lulutoy1 小时前
338. 比特位计数(leetcode)
算法·leetcode·动态规划
编码时空的诗意行者1 小时前
深入探讨C++的高级反射机制
开发语言·c++·反射机制·内省·模板编程
码力码力我爱你1 小时前
C++自定义智能指针
开发语言·c++·算法
激昂~逐流1 小时前
c++ sort比较函数的使用
c++·sort·比较函数
算法金1 小时前
算法金 | 协方差、方差、标准差、协方差矩阵
线性代数·算法·矩阵
枫yy2 小时前
算法 —— 双指针
数据结构·c++·算法·leetcode