基于s值建立线段树
从左到右 对于i 利用线段树维护 [1,i-1] 范围内 s值比s[i]小的元素中c值最小的是多少 再从右到左跑一遍
似乎dp也可以写 只是复杂度要高许多
#include <bits/stdc++.h> using namespace std; #define ll long long #define N 0x3f3f3f3f3f3f3f3f struct node { int l; int r; ll val; }; map <ll,int> mp; node tree[2][12010]; ll s[3010],c[3010],pre[3010],lft[3010],rgt[3010]; int n,len; void pushup(int id,int cur) { tree[id][cur].val=min(tree[id][2*cur].val,tree[id][2*cur+1].val); return; } void build(int id,int l,int r,int cur) { int m; tree[id][cur].l=l; tree[id][cur].r=r; tree[id][cur].val=N; if(l==r) return; m=(l+r)/2; build(id,l,m,2*cur); build(id,m+1,r,2*cur+1); return; } ll query(int id,int pl,int pr,int cur) { ll res; if(pl<=tree[id][cur].l&&tree[id][cur].r<=pr) { return tree[id][cur].val; } res=N; if(pl<=tree[id][2*cur].r) res=min(res,query(id,pl,pr,2*cur)); if(pr>=tree[id][2*cur+1].l) res=min(res,query(id,pl,pr,2*cur+1)); return res; } void update(int id,int tar,ll val,int cur) { if(tree[id][cur].l==tree[id][cur].r) { tree[id][cur].val=min(tree[id][cur].val,val); return; } if(tar<=tree[id][2*cur].r) update(id,tar,val,2*cur); else update(id,tar,val,2*cur+1); pushup(id,cur); return; } int main() { ll minn; int i; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%lld",&s[i]); pre[i]=s[i]; } for(i=1;i<=n;i++) { scanf("%lld",&c[i]); } sort(pre+1,pre+n+1); len=unique(pre+1,pre+n+1)-pre-1; for(i=1;i<=len;i++) { mp[pre[i]]=i; } build(0,1,len,1); memset(lft,0x3f,sizeof(lft)); for(i=1;i<=n;i++) { if(mp[s[i]]-1>=1) { lft[i]=query(0,1,mp[s[i]]-1,1); } update(0,mp[s[i]],c[i],1); } build(1,1,len,1); memset(rgt,0x3f,sizeof(rgt)); for(i=n;i>=1;i--) { if(mp[s[i]]+1<=len) { rgt[i]=query(1,mp[s[i]]+1,len,1); } update(1,mp[s[i]],c[i],1); } minn=N; for(i=1;i<=n;i++) { minn=min(minn,lft[i]+c[i]+rgt[i]); } if(minn==N) printf("-1\n"); else printf("%lld\n",minn); return 0; }