題意:
構造一棵2*n個節點的樹,對於節點2*i-1和節點2*i的距離爲d[i],保證有解
思路:
把奇數的點排在一起組成鏈,然後偶數只需要根據對應那個點的位置和距離算一下要被安排在哪,直接做的話會有些問題。
把每一對[2x-1,x]根據距離排序,優先安排距離大的,如果偶數節點要安排的位置比鏈尾要大了,那麼直接插入一個到鏈尾即可,而且要優先考慮插,其次考慮掛在已有的鏈上。
由於距離是遞減的,每個偶數點要麼可以插入到已有的鏈尾,要麼就必定可以掛在已有鏈上的一個點。
參考代碼:
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
struct node{
int a,b,v;
bool operator <(const node &t)const {
return v>t.v;
}
}p[N];
int mp[2*N];
int num[2*N];
vector<int>yu[2*N];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&p[i].v);
p[i].a=i*2-1;
p[i].b=i*2;
}
sort(p+1,p+1+n);
int head=0,tail=n;
for(int i=1;i<=n;i++){
if (!mp[p[i].a]) {
mp[p[i].a] = ++head;
num[head] = p[i].a;
}
int l = mp[p[i].a];
int r = l + p[i].v;
if(!num[r]&&r==tail+1){//優先插入
num[r]=p[i].b;
tail++;
continue;
}
r--;//掛的位置要減1
if(r==tail+1)tail++;
if (num[r]||r<=n) {
yu[r].push_back(p[i].b);
} else {
num[r] = p[i].b;
}
}
for(int i=1;i<tail;i++){
printf("%d %d\n",num[i],num[i+1]);
}
for(int i=1;i<=tail;i++){
for(int v:yu[i]){
printf("%d %d\n",num[i],v);
}
}
return 0;
}