预处理出每个原子最近的不能合并的位置
枚举当前位置和前面断开的位置合并
发现还是不能过
考虑用选段树优化
但是因为每次转移的最优点是在前面可以合并的范围内 dp值加上当前的到该点的最大值
因为每个位置的最大值每次更新不是只更新一个位置
是一次更新一段位置
所以直接维护复杂度爆炸
有种方法(套路) 是把最值的更新改为值的加减
因为每次是更新一段区间
且每个点到当前的位置的最值是单调不减的
所以每次的修改就可以是一段一段的
可以用单调栈来维护每种值的区间
就可以进行区间修改
#include<bits/stdc++.h> using namespace std; #define ll long long #define C getchar()-48 inline ll read() { ll s=0,r=1; char c=C; for(;c<0||c>9;c=C) if(c==-3) r=-1; for(;c>=0&&c<=9;c=C) s=(s<<3)+(s<<1)+c; return s*r; } const int N=1e5+10,inf=1e9; int n,qm; int p[N],v[N],q[N]; int vis[N]; int dp[N]; int dv[N],dr[N],top; struct xin{ int del,mn; }tr[N<<2]; inline void up(int x) { tr[x].mn=min(tr[x<<1].mn,tr[x<<1|1].mn)+tr[x].del; } inline void down(int x) { tr[x<<1].del=tr[x<<1|1].del=tr[x].del; tr[x].del=0; } inline void add(int x,int l,int r,int ql,int qr, int v) { if(ql<=l&&r<=qr){tr[x].del+=v,tr[x].mn+=v;return;} int mid=(l+r)>>1; if(ql<=mid) add(x<<1,l,mid,ql,qr,v); if(mid<qr) add(x<<1|1,mid+1,r,ql,qr,v); up(x); } inline int ask(int x,int l,int r,int ql,int qr) { if(ql<=l&&r<=qr){return tr[x].mn;} int mid=(l+r)>>1,mn=inf; if(ql<=mid) mn=min(mn,ask(x<<1,l,mid,ql,qr)); if(mid<qr) mn=min(mn,ask(x<<1|1,mid+1,r,ql,qr)); up(x); return mn+tr[x].del; } int main() { freopen("array.in","r",stdin); freopen("array.out","w",stdout); n=read();qm=n;vis[0]=1;dv[0]=inf;dr[0]=0; for(int i=1;i<=n;i++) p[i]=read(),v[i]=read(); for(int i=n;i>=1;i--) { while(!vis[p[qm]]){vis[p[qm]]=1;qm--;} q[i]=qm; vis[p[i]]=0; } for(int i=1;i<=n;i++) { add(1,1,n,i,i,v[i]); while(dv[top]<v[i]) { add(1,1,n,dr[top-1]+1,dr[top],v[i]-dv[top]); top--; } dv[++top]=v[i],dr[top]=i; dp[i]=ask(1,1,n,q[i]+1,i); add(1,1,n,i+1,i+1,dp[i]); } cout<<dp[n]; return 0; }
还有位大佬用multiset维护
#include<bits/stdc++.h> using namespace std; #define Abigail inline void typedef long long LL; const int N=100000,INF=(1<<30)-1; multiset<int>t; int n,a[N+9],b[N+9],data[N+9],last[N+9],l[N+9]; int sum[N+9],wei[N+9],f[N+9],hd,tl; Abigail into(){ scanf("%d",&n); for (int i=1;i<=n;++i) scanf("%d%d",&a[i],&b[i]); } Abigail work(){ for (int i=1;i<=n;++i) l[i]=max(l[i-1],last[a[i]]+1),last[a[i]]=i; //预处理每一个位置为结尾可以取的转移的区间左端点 hd=1; int k; for (int i=1;i<=n;++i){ k=i-1; for (;hd<tl&&wei[hd+1]<l[i];++hd) t.erase(t.find(sum[hd])); //把不在转移区间的位置去掉 for (;hd<=tl&&b[i]>data[tl];--tl) t.erase(t.find(sum[tl])),k=wei[tl]; //更新阶梯型(max{b[j]..b[i]}) data[++tl]=b[i]; wei[tl]=k; //加入第i个位置 if (hd^tl){ sum[tl]=f[wei[tl]]+data[tl]; //把位置i所在的阶梯中最优的值sum[tl]计算出来 t.insert(sum[tl]); //加入set中 t.erase(t.find(sum[hd])); //开头的那一段阶梯中会有一部分不可取,一部分可取 } sum[hd]=f[l[i]-1]+data[hd]; //采取开头最优的那段 t.insert(sum[hd]); //加入set中 f[i]=*t.begin(); } } Abigail outo(){ printf("%d ",f[n]); } int main(){ freopen("array.in","r",stdin); freopen("array.out","w",stdout); into(); work(); outo(); return 0; }