Description
Input
输入的第一行包含整数n和k,其中n(2 ≤ n ≤100 000)表示办公楼的数目,k(1≤ k≤ n/2)表示可利用的网络电缆的数目。接下来的n行每行仅包含一个整数(0≤ s ≤1000 000 000), 表示每个办公楼到大街起点处的距离。这些整数将按照从小到大的顺序依次出现。
Output
输出应由一个正整数组成,给出将2K个相异的办公楼连成k对所需的网络电缆的最小总长度。
Sample Input
5 2
1
3
4
6
12
1
3
4
6
12
Sample Output
4
HINT
上面的样例输入给出了前面描述的示例情形 对于每一个测试点,如果写到输出文件中的答案正确,则得到该测试点100%的分数,否则得零分。30%的输入数据满足n≤20。60%的输入数据满足n≤10 000。
题解:
观察一下发现就是种树。。
#include<iostream>
#include<cstdio>
#define p 0x7fffffff
using namespace std;
int n,m,pos[200001],h[200001],l[200001],r[200001],u;
long long a[200001],b[200001],ans;
void up(int x)
{
while (x>1)
{
if (a[h[x]]<a[h[x>>1]])
{
swap(h[x],h[x>>1]);
swap(pos[h[x]],pos[h[x>>1]]);
x=x>>1;
}
else break;
}
}
void down(int x)
{
int u;
while (x<<1<=n)
{
if (a[h[x<<1]]<a[h[x<<1|1]]||x<<1==n) u=x<<1;
else u=x<<1|1;
if (a[h[x]]>a[h[u]])
{
swap(h[u],h[x]);
swap(pos[h[u]],pos[h[x]]);
x=u;
}
else break;
}
}
int main()
{
scanf("%d%d",&n,&m);
scanf("%lld",&b[0]);
a[0]=p;a[n]=p;
for (int i=1;i<=n-1;i++)
{
scanf("%lld",&b[i]);
a[i]=b[i]-b[i-1];
l[i]=i-1;r[i]=i+1;pos[i]=h[i]=i;
up(i);
}
for (int i=1;i<=m;i++)
{
u=h[1];
ans+=a[u];a[u]=a[l[u]]+a[r[u]]-a[u];
a[l[u]]=p;down(pos[l[u]]);
a[r[u]]=p;down(pos[r[u]]);
down(1);
l[u]=l[l[u]];r[u]=r[r[u]];l[r[u]]=u;r[l[u]]=u;
}
cout<<ans<<endl;
}