【洛谷】P1878 舞蹈课(链表+二叉堆)
题意
给定\(n\)个人,每个人有一个舞蹈技术值,相邻且舞蹈技术值相差最小的一对异性会出队,求出队的总次数以及出队的顺序。
思路
首先看到最小值,可以想到用小根堆来实现。
先将每一种可能的出队方案储存到小根堆中。
可以定义一个数组来表示是否出队。如果相邻的舞者有人已经出队,便跳过。
每一次出队以后,就会产生一对新的相邻舞者,可以用数组模拟链表来储存每一位舞者边上的人。出队后便将这一对舞者从链表中删去,同时在答案数组中记录。再判断新产生的一对相邻舞者是否满足出队要求(注意特判边界情况)。
最终得到的便是本题的答案。
代码
#include<cstdio>
#include<queue>
using namespace std;
const int N=2e5+10;
int n,a[N],nex[N],sex[N],pre[N],ans[N][2],cnt;
bool st[N];
char s[N];
int abs(int a){return a>0?a:-a;}
struct node{
int l,r,dis;
bool operator <(const node &t)const{
if(dis==t.dis) return l>t.l; //若有多队舞者差值相同,则最左边的一对优先出队
return dis>t.dis;
}
};
priority_queue<node>q;
int main()
{
scanf("%d",&n);
scanf("%s",s+1);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(s[i]=='B') sex[i]=1;
pre[i]=i-1,nex[i]=i+1; //链表初始化
}
for(int i=1;i<n;i++)
if((sex[i]^sex[i+1])==1) q.push(node{i,i+1,abs(a[i]-a[i+1])});// 若相邻两人异性,则异或值为1,反之则为0
while(q.size())
{
node now=q.top();
q.pop();
if(!st[now.l]&&!st[now.r]) //都仍未出队
{
st[now.l]=true;//标记出队
st[now.r]=true;
ans[++cnt][0]=now.l;//记录答案
ans[cnt][1]=now.r;
nex[pre[now.l]]=nex[now.r];//删去出队的舞者
pre[nex[now.r]]=pre[now.l];
if(nex[now.r]>n||pre[now.l]<1) continue; //特判边界
if((sex[pre[now.l]]^sex[nex[now.r]])==1) q.push(node{pre[now.l],nex[now.r],abs(a[pre[now.l]]-a[nex[now.r]])});
//判断新产生的相邻舞者是否满足出队要求
}
}
printf("%d\n",cnt);
for(int i=1;i<=cnt;i++) printf("%d %d\n",ans[i][0],ans[i][1]);
return 0;
}

浙公网安备 33010602011771号