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;
}
*:中间爆了本地的栈,开了无限栈后知道稳过了。

浙公网安备 33010602011771号