一眼笛卡尔树,这样我们得到了 O ( n m ) O(nm) O(nm)的 D P DP DP做法。
有一步 非常关键 的转化:考虑求能保留下来的星座的最大价值。
为什么要这么转化?因为这样好算贡献!
考虑优化,设 d p i , j dp_{i,j} dpi,j表示 i i i为根的子树,只考虑高度 ≤ j \le j ≤j的星星,能保留下来的星座的最大价值。
写出 D P DP DP式子:
1.1 1.1 1.1 d p i , j = d p l , j + d p r , h i dp_{i,j}=dp_{l,j}+dp_{r,h_i} dpi,j=dpl,j+dpr,hi
1.2 1.2 1.2 d p i , j = d p r , j + d p l , h i dp_{i,j}=dp_{r,j}+dp_{l,h_i} dpi,j=dpr,j+dpl,hi
1.3 1.3 1.3 d p i , j = d p l , h i + d p r , h i + val ( i , j ) dp_{i,j}=dp_{l,h_i}+dp_{r,h_i}+\text{val}(i,j) dpi,j=dpl,hi+dpr,hi+val(i,j)
发现合法状态数目其实是 区间内星星的数量,并且 只需要保留 j ≥ h i j\ge h_i j≥hi部分的 D P DP DP值 即可。
这个形式非常优美,直接写一发线段树合并即可。
复杂度 O ( n log n ) O(n\log n) O(nlogn)。
remark \text{remark} remark 第一步转化真的非常重要!!否则后面的 D P DP DP式子有很大一堆!就因为这个我自闭了一天。
#include
#define fi first
#define se second
#define ll long long
#define pb push_back
#define db double
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N=2e5+5;
const int M=N*40;
int n,m,tot,rt[N],h[N];
int nxt[N],sum[N];
//建立笛卡尔树即可
struct node{
int l,r;
ll max,add;
}t[M];
vector<pair<int,int>>points[N];
int s[N],cnt,ls[N],rs[N];
void build(){
for(int i=1;i<=n;i++){
int tmp=0;
while(cnt&&h[s[cnt]]<h[i])tmp=s[cnt--];
ls[i]=tmp;if(cnt)rs[s[cnt]]=i;
s[++cnt]=i;
}
}
void add(int p,ll x){
if(!p)return;t[p].max+=x,t[p].add+=x;
}
void pushup(int p){
t[p].max=max(t[t[p].l].max,t[t[p].r].max);
}
void pushdown(int p){
if(t[p].add)add(t[p].l,t[p].add),add(t[p].r,t[p].add),t[p].add=0;
}
ll query(int p,int l,int r,int ql,int qr){
if(!p||ql>qr)return 0;
if(ql<=l&&r<=qr)return t[p].max;
int mid=l+r>>1;pushdown(p);
if(qr<=mid)return query(t[p].l,l,mid,ql,qr);
if(mid<ql)return query(t[p].r,mid+1,r,ql,qr);
return max(query(t[p].l,l,mid,ql,qr),query(t[p].r,mid+1,r,ql,qr));
}
void modify(int &p,int l,int r,int x,ll y){
if(!p)p=++tot;
if(l==r){
t[p].max=max(t[p].max,y);
return;
}
int mid=l+r>>1;pushdown(p);
x<=mid?modify(t[p].l,l,mid,x,y):modify(t[p].r,mid+1,r,x,y);
pushup(p);
}
int merge(int p,int q,int l,int r){
if(!p||!q)return p+q;
if(l==r){
t[p].max=max(t[p].max,t[q].max);
return p;
}
int mid=l+r>>1;pushdown(p),pushdown(q);
t[p].l=merge(t[p].l,t[q].l,l,mid),t[p].r=merge(t[p].r,t[q].r,mid+1,r);
pushup(p);return p;
}
void solve(int u){
if(!u)return;
int l=ls[u],r=rs[u];
solve(l),solve(r);
ll c1=query(rt[l],1,n,1,h[u]),c2=query(rt[r],1,n,1,h[u]);
add(rt[l],c2),add(rt[r],c1);
for(auto x:points[u])modify(rt[u],1,n,x.fi,x.se+c1+c2);
modify(rt[u],1,n,h[u],c1+c2);
rt[u]=merge(merge(rt[l],rt[r],1,n),rt[u],1,n);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n;for(int i=1;i<=n;i++)cin>>h[i];
ll sum=0;
cin>>m;for(int i=1;i<=m;i++){
int x,y,c;cin>>x>>y>>c;sum+=c;
points[x].pb({y,c});
}
build();solve(s[1]);cout<<sum-t[rt[s[1]]].max;
}