MnZn #20 WA 求调
查看原帖
MnZn #20 WA 求调
448593
Scorilon楼主2025/8/3 12:09

思路是用小根堆维护,每取出一个最小的结果就把旁边的两个结点的权值之和减去当前结点权值放入原来这三个结点所在的位置并插入堆中,用链表维护随机位置插入.

#20 所得结果比正确答案小.

#include <queue>
#include <cstdio>
#include <algorithm>

typedef long long ll;

const int N=1e5+10;

ll val[N<<1];
int prev[N<<1],next[N<<1],tot=2,head,tail;

void init() {
	head=1;tail=2;
	next[head]=tail;
	prev[tail]=head;
	val[head]=val[tail]=0x7fffffff;
}

int insert(int pos,ll x) {
	int p=++tot;val[p]=x;
	prev[next[pos]]=p;
	next[p]=next[pos];
	next[pos]=p;prev[p]=pos;
	return p;
}

void remove(int p) {
	prev[next[p]]=prev[p];
	next[prev[p]]=next[p];
}

void print() {
	puts("qwq");
	for(int i=next[head];i!=tail;i=next[i]) printf("%d ",val[i]);
	puts("\n---");
}

int n,k;
bool vis[N<<1];
std::priority_queue<std::pair<ll,int>> q;

int main() {
	init();
	scanf("%d%d",&n,&k);
	for(int i=0,s=0,last=0;i<n;i++) {
		scanf("%d",&s);
		if(i) q.push(std::make_pair(last-s,insert(i==1?i:i+1,s-last)));
		last=s;
	}
	ll ans=0;
	for(int i=1;i<=k;i++) {
		while(vis[q.top().second]) q.pop();
		if(!q.empty()) {
			auto cur=q.top();
			q.pop();
			ans-=cur.first;
			ll x=cur.first;
			x+=val[prev[cur.second]];x+=val[next[cur.second]];
			vis[cur.second]=vis[prev[cur.second]]=vis[next[cur.second]]=true;
			q.push(std::make_pair(-x,insert(prev[prev[cur.second]],x)));
			remove(prev[cur.second]);remove(next[cur.second]);remove(cur.second);
		}
	}
	printf("%lld\n",ans);
	return 0;
}
2025/8/3 12:09
加载中...