ARC159D-solution
PART 0
wtcl。
PART 1
给出
PART 2
首先,这是一道线段树优化 dp。
没错,就是 dp。
我们首先想朴素的 dp 方程。
考虑设
肯定是要枚举之前的
那么就有两种情况:
这种情况就说明
那么新加的长度就是区间
这种情况就说明新加的是
那么新加的长度就是
综上,
但是这样做是
PART 3
我们考虑线段树优化。
根据上个式子,我们可以发现与
所以我们可以用两棵下标为
这样我们每次只需要取出
PART 4
需要离散化。
#include<bits/stdc++.h>
using namespace std;
#define N 200001
int z[N<<3][3],l[N],r[N];//val:离散化之后的r[i]
int n,m,i,j,k,s,now,ans,cnt;
vector<int> val;
//z[p][1]维护dp[j]
//z[p][2]维护dp[j]-r[j]
void make_tree(int p,int l,int r,int now)
{
z[p][now]=-1e9;
if(l==r)return;
z[p][now]=0;
int mid=(l+r)>>1;
make_tree(p<<1,l,mid,now);
make_tree(p<<1|1,mid+1,r,now);
z[p][now]=max(z[p<<1][now],z[p<<1|1][now]);
}
void add(int p,int l,int r,int d,int to,int now)
{
if(l==r)
{
z[p][now]=max(z[p][now],d);
return;
}
int mid=(l+r)>>1;
if(to>mid)add(p<<1|1,mid+1,r,d,to,now);
else add(p<<1,l,mid,d,to,now);
z[p][now]=max(z[p<<1][now],z[p<<1|1][now]);
}
int query(int p,int l,int r,int k,int s,int now)
{
if(k<=l&&r<=s)return z[p][now];
int mid=(l+r)>>1,ans=-1e9;
if(k<=mid)ans=max(ans,query(p<<1,l,mid,k,s,now));
if(s>mid)ans=max(ans,query(p<<1|1,mid+1,r,k,s,now));
return ans;
}
int main()
{
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d%d",&l[i],&r[i]);
val.push_back(l[i]);
val.push_back(r[i]);//l[i],r[i]都需要离散化
}
val.push_back(0);
sort(val.begin(),val.end());
val.erase(unique(val.begin(),val.end()),val.end());
m=val.size();//离散化用了vector,其实可以用数组
make_tree(1,1,m,1);
make_tree(1,1,m,2);
add(1,1,m,0,1,1);
add(1,1,m,0,1,2);
for(i=1;i<=n;i++)
{
k=lower_bound(val.begin(),val.end(),l[i])-val.begin()+1;
s=lower_bound(val.begin(),val.end(),r[i])-val.begin()+1;//查询离散化之后的l[i],r[i]
now=max(query(1,1,m,1,k-1,1)+r[i]-l[i]+1,query(1,1,m,k,s,2)+r[i]);
ans=max(ans,now);//now即为当前的dp[i],只不过省略了dp数组
add(1,1,m,now,s,1);
add(1,1,m,now-r[i],s,2);
}
printf("%d",ans);
return 0;
}