#dp,KTT#CF1830F The Third Grace
题目
有一条数轴,上面有 \(n\) 个区间和 \(m\) 个点,第 \(i\) 个区间覆盖坐标 \([l_i,r_i]\),
第 \(i\) 个点在坐标 \(i\) 处,具有权值 \(p_i\)。
最初,所有点都未激活。对于第 \(i\) 个区间,我们定义它的代价为:
若区间内没有被激活的点,则代价为 \(0\);否则,代价为在区间内坐标最大的被激活点的权值。
你需要选择一些点来激活,使所有区间的代价之和最大,求这个最大值。
分析
设 \(dp[i]\) 表示激活 \(i\) 以及 \(i\) 之前的点能获得的最大代价,那么答案就是所有 \(dp\) 的最大值。
考虑把它扔到线段树上,那么 \(dp[i]=dp[j]+k[i]\times p[i]\),将区间按右端点排序。
那么每个区间都会给 \(dp_{l\sim r}\) 的 \(k\) 各加上一,而且是不断增大的,那么就可以用 KTT 来做。
代码
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long lll; const lll inf=1e18;
const int N=1000011;
struct node{int y,next;}e[N];
int a[N],n,m,T,as[N];
struct rec{lll sum,lmax,rmax,w;};
struct Segment_Tree{
lll K[N<<2],B[N<<2],bound[N<<2],lazy[N<<2];
void pmax(lll k1,lll b1,lll k2,lll b2,lll &k,lll &b,lll &bound){
if (b1<b2||(b1==b2&&k1<k2)) swap(k1,k2),swap(b1,b2);
k=k1,b=b1;
if (k1<k2) bound=min(bound,(b1-b2)/(k2-k1));
}
void pup(int k){
bound[k]=min(bound[k<<1],bound[k<<1|1]);
pmax(K[k<<1],B[k<<1],K[k<<1|1],B[k<<1|1],K[k],B[k],bound[k]);
}
void ptag(int k,lll z){
B[k]+=K[k]*z,lazy[k]+=z;
if (bound[k]!=inf) bound[k]-=z;
}
void build(int k,int l,int r){
lazy[k]=0;
if (l==r){
K[k]=a[l],B[k]=0,bound[k]=inf;
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
pup(k);
}
void update(int k,int l,int r,int x,lll y){
if (l==r){
lazy[k]=0,B[k]=y;
return;
}
int mid=(l+r)>>1;
if (x<=mid) update(k<<1,l,mid,x,y);
else update(k<<1|1,mid+1,r,x,y);
pup(k);
}
void update(int k,int l,int r,int x,int y,lll z){
if (l==x&&r==y&&z<=bound[k]){
ptag(k,z);
return;
}
int mid=(l+r)>>1;
if (lazy[k]){
ptag(k<<1,lazy[k]);
ptag(k<<1|1,lazy[k]);
lazy[k]=0;
}
if (y<=mid) update(k<<1,l,mid,x,y,z);
else if (x>mid) update(k<<1|1,mid+1,r,x,y,z);
else update(k<<1,l,mid,x,mid,z),update(k<<1|1,mid+1,r,mid+1,y,z);
pup(k);
}
lll query(int k,int l,int r,int x,int y){
if (l==x&&r==y) return B[k];
int mid=(l+r)>>1;
if (lazy[k]){
ptag(k<<1,lazy[k]);
ptag(k<<1|1,lazy[k]);
lazy[k]=0;
}
if (y<=mid) return query(k<<1,l,mid,x,y);
else if (x>mid) return query(k<<1|1,mid+1,r,x,y);
else return max(query(k<<1,l,mid,x,mid),query(k<<1|1,mid+1,r,mid+1,y));
}
}Tre;
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
for (cin>>T;T;--T){
cin>>m>>n;
for (int i=1;i<=m;++i){
int l,r; cin>>l>>r;
e[i]=(node){l,as[r]},as[r]=i;
}
for (int i=1;i<=n;++i) cin>>a[i];
Tre.build(1,1,n);
for (int i=1;i<=n;++i){
Tre.update(1,1,n,i,i>1?Tre.query(1,1,n,1,i-1):0);
for (int j=as[i];j;j=e[j].next)
Tre.update(1,1,n,e[j].y,i,1);
}
cout<<Tre.B[1]<<'\n';
for (int i=1;i<=n;++i) as[i]=0;
}
return 0;
}

浙公网安备 33010602011771号