Luogu P1878
事實上這道題並不難,但我真沒弄懂我手寫堆爲什麼過不了。所以
STL大法好!!!
基本思路
對於每一對相鄰異性,將他們的舞蹈技術的差插入一個堆
通過維護這個小根堆,每次就可以取得舞蹈技術差最小的一對
值得注意的是,每次取完一對舞伴之後,要對這對舞伴進行標記,並將堆中所有有這兩位舞者參與的舞伴彈出這個堆。並且還需要找到這一對舞伴兩邊的第一個未被挑出的人,如果是異性則可以作爲新的舞伴加入堆
代碼
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
struct data
{
int l,r,val;
bool operator <(const data&x) const
{
if (x.val!=val) return x.val<val;
else return x.l<l;
}//重載運算符
};
int len,n,que[200005],a[200005],ans,group1[200005],group2[200005],rlen;
bool choice[200005];
priority_queue <data> heap;
int main()
{
scanf("%d\n",&n);
for (int i=1;i<=n;i++)
{
char c;
scanf("%c",&c);
if (c=='B') que[i]=true;//對男生進行標記
}
scanf("%d",&a[1]);
for (int i=2;i<=n;i++)
{
scanf("%d",&a[i]);
if (que[i]!=que[i-1]) //可以組成舞伴則進堆
{
data rec;
rec.l=i-1;rec.r=i;
rec.val=abs(a[i]-a[i-1]);
heap.push(rec);
}
}
while (!heap.empty())
{
data rec=heap.top();
ans++;
group1[ans]=rec.l;
group2[ans]=rec.r;
choice[rec.l]=choice[rec.r]=true;//打上標記
while (choice[rec.l]||choice[rec.r])
{
if (heap.empty()) break;
heap.pop();
rec=heap.top();
}//這一個循環的目的就是使堆頂元素是沒有被選過的
int l=group1[ans];int r=group2[ans];
while (l>0&&choice[l]) l--;
while (r<=n&&choice[r]) r++;
//尋找兩邊未被選的人
if (que[l]!=que[r]&&l>0&&r<=n)
{
rec.l=l;
rec.r=r;
rec.val=abs(a[l]-a[r]);
heap.push(rec);
}
}
printf("%d\n",ans);
for (int i=1;i<=ans;i++) printf("%d %d\n",group1[i],group2[i]);
return 0;
}