对于这个dp转移方程,我们观察到的是每个点都从左上方转移或者上方转移。
如果从左上方转移,那么多了一个b[i],可见我们对于每一行在第几列,就能获得几个b[i],那么这其实就是求区间的前k大值和
这就是主席树模板题
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=2e5+10; int rt[N],idx; ll pre[N]; int a[N]; vector<int> num; struct node{ int l,r; int cnt; ll sum; ll d; }tr[N*40]; int n; void init(){ pre[1]=1; for(ll i=2;i<=100005;i++) pre[i]=pre[i-1]+i*i; } void build(int &p,int l,int r){ p=++idx; if(l==r){ return ; } int mid=l+r>>1; build(tr[p].l,l,mid); build(tr[p].r,mid+1,r); } int find(int x){ return lower_bound(num.begin(),num.end(),x)-num.begin()+1; } void insert(int &p,int q,int l,int r,int pos,int cnt){ p=++idx,tr[p]=tr[q]; tr[p].cnt+=1,tr[p].sum+=cnt; if(l==r){ tr[p].d=cnt; return ; } int mid=l+r>>1; if(pos<=mid) insert(tr[p].l,tr[q].l,l,mid,pos,cnt); else insert(tr[p].r,tr[q].r,mid+1,r,pos,cnt); } ll query(int p,int q,int l,int r,int k){ if(l==r){ return tr[p].d*k; } int cnt=tr[tr[p].r].cnt-tr[tr[q].r].cnt; int mid=l+r>>1; if(k<=cnt){ return query(tr[p].r,tr[q].r,mid+1,r,k); } else{ return tr[tr[p].r].sum-tr[tr[q].r].sum+query(tr[p].l,tr[q].l,l,mid,k-cnt); } } int main(){ //ios::sync_with_stdio(false); int t; cin>>t; init(); while(t--){ cin>>n; int i; idx=0; num.clear(); for(i=1;i<=n;i++){ scanf("%d",&a[i]); num.push_back(a[i]); rt[i]=0; } build(rt[0],1,n); sort(num.begin(),num.end()); num.erase(unique(num.begin(),num.end()),num.end()); for(i=1;i<=n;i++){ insert(rt[i],rt[i-1],1,n,find(a[i]),a[i]); } int l,r,k; int q; cin>>q; while(q--){ scanf("%d%d%d",&l,&r,&k); printf("%lld ",pre[(r-l+1)]+query(rt[r],rt[l-1],1,n,k)); } } }