2024-9-19 比赛总结

今天,状态还行。

T1

\(30 min\) 就已经想到 \(O(n\log n)\) 的贪心,即每次在最大值的旁边,次大值的方向断边。
本来想在每次分段后用 \(n\log n\) 的时间,将数放到优先队列里求最大次大值,发现在平添 \(\log\),就每次 \(O(n)\) 找最大值,成功做出暴力,拿到大约 \(40pts\)
后来发现复杂度不对,花了将近 \(90min\) 写了线段树将找最大值优化为了 \(O(\log n)\) 的,同时做了一些小优化,拿下此题*。

//24-9-19 by _maple_leaf_
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=200010;
int C,T;
int ans;
int n,a[N];
struct node{
	int t,id;
}tr[N<<3];
inline void init(int id,int l,int r){
	int mid=l+r>>1;
	if(l==r){
		tr[id].t=a[l];
		tr[id].id=l;
		return ;
	}
	init(id<<1,l,mid),init(id<<1|1,mid+1,r);
	if(tr[id<<1].t>=tr[id<<1|1].t)tr[id]=tr[id<<1];
	else tr[id]=tr[id<<1|1];
}
inline node find(int id,int l,int r,int s,int e){
	if(s>e)return {0,0};
	if(l>r)return {0,0};
	if(s<=l&&r<=e)return tr[id];
	int mid=l+r>>1,ret=0,reti=0;
	if(s<=mid){
		node tmp=find(id<<1,l,mid,s,e);
		if(ret<tmp.t){
			ret=tmp.t;
			reti=tmp.id;
		}
	}
	if(mid<e){
		node tmp=find(id<<1|1,mid+1,r,s,e);
		if(ret<tmp.t){
			ret=tmp.t;
			reti=tmp.id;
		}
	}
	return {ret,reti};
}
inline void f(int st,int ed,int mx,int id){
	if(st>=ed)return ;
	node t1=find(1,1,n,st,id-1),t2=find(1,1,n,id+1,ed);
	int mx1=0,id1=0;
	if(t1.t>=t2.t){
		mx1=t1.t;
		id1=t1.id;
	}else{
		mx1=t2.t;
		id1=t2.id;
	}
	ans+=mx-mx1;
	if(id<id1)f(st,id,mx,id),f(id+1,ed,mx1,id1);
	else f(st,id-1,mx1,id1),f(id,ed,mx,id);
}
signed main(){
	freopen("chain.in","r",stdin);
	freopen("chain.out","w",stdout);
	scanf("%lld%lld",&C,&T);
	while(T--){
		ans=0;
		scanf("%lld",&n);
		int mx=0,id=0;
		bool f1=1,f2=1;
		for(int i=1;i<=n;++i){
			scanf("%lld",&a[i]);
			if(mx<a[i]){
				mx=a[i];
				id=i;
			}
			if(a[i]<a[i-1])f2=0;
			if(a[i]>a[i-1])f1=0;
		}
		if(f1||f2)for(int i=1;i<n;++i)ans+=abs(a[i+1]-a[i]);
		else{
			init(1,1,n);
			f(1,n,mx,id);
		}
		printf("%lld\n",ans);
	}
	return 0;
}

*:中间爆了本地的栈,开了无限栈后知道稳过了。

posted @ 2024-09-19 16:57  BriskCube  阅读(16)  评论(0)    收藏  举报