洛谷题单指南-二叉堆与树状数组-P1878 舞蹈课

原题链接:https://www.luogu.com.cn/problem/P1878

题意解读:n个男女排列一行,每人舞蹈技术是ai,每次找到相邻男女舞蹈技术差值绝对值最小的一对出列,输出每对出列的人员编号。

解题思路:

设初始有8人编号为:1 2 3 4 5 6 7 8

将1 2, 2 3, 3 4, 4 5, 5 6, 6 7, 7 8中是男女的配对编号以及ai的差值存入小根堆

循环处理小根堆堆顶

假设第一次出列的配对是4 5

那么与4和5相关的其他配对就没有存在的必要,如3 4,5 6这些配对在处理时可以舍去

另外,由于4 5出列,队伍变成1 2 3 6 7 8

3 6会成为新的可能的配对,需要动态加入小根堆

两个关键问题:

1、当一组配对出列后,与配对相关的其他配合如何舍去

可以借助标记数组flag[N],记录每个编号是否出列,当取优先队列堆顶时,判断该组配对里的人员是否已经出列,如果出列则舍去

2、当一组配对出列后,该配对两侧的人会产生新的配对

可以通过ll[N],rr[N]两个数组,动态维护每个编号左边是谁、右边是谁,这样当有配对出列,只需要取配对左边人员的左边,配对右边人员的右边,组成新的配对即可

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 200005;
int n;
char s[N];
int a[N];
bool flag[N]; //标记已出列的编号
int ll[N], rr[N]; //每个人左边、右边是谁
struct Node
{
    int l, r;
    bool operator < (const Node &node) const &
    {
        if(abs(a[l] - a[r]) != abs(a[node.l] - a[node.r]))
            return abs(a[l] - a[r]) > abs(a[node.l] - a[node.r]); //差值绝对值小的在堆顶
        return l > node.l; //差值一样,更左边的在堆顶
    }
};
priority_queue<Node> q; //保存潜在的配对
int ansl[N], ansr[N], cnt;

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> s[i];
    for(int i = 1; i <= n; i++)
    {
        cin >> a[i];
        ll[i] = i - 1;
        rr[i] = i + 1;

        if(i > 1)
        {
            if(s[i] != s[i - 1])
            {
                q.push({i - 1, i});
            }
        }
    } 

    while(q.size())
    {
        if(flag[q.top().l] || flag[q.top().r]) //如果配对中的某个已经出列,该配对也不存在
        {
            q.pop();
            continue;
        }
        Node node = q.top(); q.pop();
        cnt++;
        ansl[cnt] = node.l;
        ansr[cnt] = node.r;
        flag[node.l] = flag[node.r] = true; //标记已出列
        int node_left = ll[node.l]; //已出列配对左边的左边
        int node_right = rr[node.r]; //已出列配对右边的右边
        if(node_left < 1 || node_right > n) continue;
        rr[node_left] = node_right; 
        ll[node_right] = node_left;
        if(s[node_left] != s[node_right]) q.push({node_left, node_right});
    }

    cout << cnt << endl;
    for(int i = 1; i <= cnt; i++) cout << ansl[i] << " " << ansr[i] << endl;

    return 0;
}

 

posted @ 2024-11-13 09:27  五月江城  阅读(6)  评论(0编辑  收藏  举报