题意:好长不想解释,扔个连接在这:传送门
思路:
首先不难发现,如果真的要建图,因为是完全图,无论是建图还是遍历图都要n方,所以不难发现这题其实不用真的建图。
考虑一下两点,不妨称为u,v的最短路有几种可能性,
1......u......v......n
若区间最小在u,v之间,则只需要直接相连即可,
若最小在左侧,则d[u,v]=最小值*2
在右侧同左侧理
所以无论如何,最小值*2一定是直径的最小值(因为一定可以这么走到)
至于如何让直径更大,就要用到k次置换的机会
不难发现,相邻的两个d[u,v]一定是最大的,所以实际上只需要考虑相邻的即可,如果相邻的能都换成1e9,则直径可以锁定成1e9
具体操作用二分答案即可,注意入果a[i]*2<mid则一定需要置换掉。消耗一个名额。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
const int inf=1e9+9;
const ll INF=1e18l;
/*
priority_queue<int> big_heep;
priority_queue<int,vector<int>,greater<int> > small_heep;
struct cmp{//if return true,it means that the number in the left was smaller than the right one
bool operator () (int a,int b){
}
};
*/
int n,k;
int a[200005];
int b[200005];
bool check(int mid){
int kk=k;
for (int i=1;i<=n;i++){
if (a[i]*2<mid){
b[i]=1e9;
kk--;
if (kk<0) return false;
}
else b[i]=a[i];
}
if (kk>=2) return true;
for (int i=2;i<=n;i++){
if (min(b[i],b[i-1])>=mid) return true;
if (max(b[i],b[i-1])>=mid and kk>=1) return true;
}
return false;
}
void work(){
cin>>n>>k;
for (int i=1;i<=n;i++) cin>>a[i];
int l=1;
int r=1e9;
while(l<r){
int mid=(l+r+1)/2;
if (check(mid)) l=mid;
else r=mid-1;
}
cout<<l<<"\n";
return;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
ll t;
cin>>t;
while (t--){
work();
}
return 0;
}