题解 P1878 【舞蹈课】
这一题大概是二叉堆也就是优先队列的题。
首先新建一个小根堆
按照题意模拟一下过程:第一遍,我们从左到右扫整个数组,如果有相邻的异性就入队。
这里在优先队列里我们存储三个信息:当前一对的编号
每一次首先从优先队列里去处队首元素,将他们标记为已取过,出队,用
看到这里,此题似乎与优先队列裸题没区别。
但是题目里说了这么一句:“一对异性出列之后,队伍中的空白按原顺序补上(即:若队伍为
这意味着什么呢?
怎么办?链表
设
首先将
然后每次进行合法的出队的操作的时候,我们把当前点对的左边的数叫
这里有点绕,简而言之就是(可以画个图试试)。
f[g[x]] = f[y];
g[f[y]] = g[x];
然后这里多出来了一对新的相邻点
判断他们是否合法,如果合法就入队即可。
代码:
#include<bits/stdc++.h>
using namespace std;
struct node{
int w,c,d;
};
priority_queue<node>q;
int n,a[200011]={0},is[200011]={0},cnt=0,ans1[200011]={0},ans2[200011]={0},f[200011]={0},g[200011]={0},flag=1;
bool operator<(node a,node b){
if(a.w==b.w)return a.c>b.c;
else return a.w>b.w;
}
string s;
int main(){
cin>>n;
cin>>s;
for(int i=1;i<=n;i++){
cin>>a[i];
}
s+='H';
for(int i=1;i<n;i++){
if(s[i-1]!=s[i])q.push((node){abs(a[i]-a[i+1]),i,i+1});
}
for(int i=1;i<=n;i++){
f[i]=i+1;
g[i]=i-1;
}
while(q.empty()==0){
node t=q.top();
q.pop();
int x=t.c,y=t.d;
if(is[x]==0&&is[y]==0){
f[g[x]]=f[y];
g[f[y]]=g[x];
cnt+=1;
ans1[cnt]=x,ans2[cnt]=y;
is[x]=1,is[y]=1;
if(is[g[x]]==0&&is[f[y]]==0){
if((s[g[x]-1]+s[f[y]-1])==('G'+'B')){
q.push((node){abs(a[g[x]]-a[f[y]]),g[x],f[y]});
}
}
}
}
cout<<cnt<<endl;
for(int i=1;i<=cnt;i++){
cout<<ans1[i]<<" "<<ans2[i]<<endl;
}
return 0;
}
最后提示一点,一定一定要先出队(具体就是用
否则会WA(因为已经有新的数进来了队首可能就变了我就是在这卡住的)
都到这了,点个赞好吗qwq