codeforces 1032 H. Ice Baby
题目链接:
https://codeforces.com/contest/2121/problem/H
思路:
-
显然题目要求从\(1-n\)的每个长度的最长不下降子序列,根据这个基本能猜到求解思路会接近每次在数组最后面添加一个数,这个数能对于我的最好答案产生什么贡献。
-
定义\(dp[i]\)为以\(i\)结尾的最长不下降子序列的长度。
-
假设我现在遍历到第\(i\)个数了,前\(i-1\)个数的所有结尾的最长不下降子序列长度我已经维护好了。显然的我暴力更新的话:我第\(i\)个数可以枚举值取\(l[i]\)到\(r[i]\)每个值,当我值取\(x\)时\(dp[x]=max(dp[x],dp[y]+1);(1 \le y\le x-1)\)。就是相当于前面接上值小于我的最长段。这个部分可以用线段树维护区间\(max\)加速。
-
然后考虑优化这部分,本质来看如果\(dp[x]\)和\(dp[y]\)相同,且满足\(x<y\),那么其实只要有\(dp[x]\)就够了。因为如果可以用\(dp[y]\)更新,那么也一定可以用\(dp[x]\)更新。
-
那么根据这个性质我们就可以优化上面的过程,只要用\(dp[x]\)更新\(dp[l[i]]\)就行\((1\le x \le l[i]-1)\)。因为假设比\(i\)大的值用的是\((1,l[i]-1)\)的\(dp\)值更新,然后这时候因为我\(dp[l]\)的值也用这部分更新了,那其实就不需要更新。同理用大于等于\(l[i]\)的\(dp\)值更新,也不需要更新。因为\(dp[l]\)更好,所以我们只要用\(dp[x]\)更新\(dp[l[i]]\)就行\((1\le x \le l[i]-1)\)。
-
然后最后别忘了还能接等于自己的产生+\(1\)的贡献,这里可以用线段树区间加更新。
-
值域较大,离散化和开点树都可以,我用的开点树。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1000100;
int l[N];
int r[N];
int tree[N<<4];
int tag[N<<4];
int L[N<<4];
int R[N<<4];
int cnt=1;
void up(int i){
tree[i]=max(tree[L[i]],tree[R[i]]);
}
void lazy(int i,int x){
tree[i]+=x;
tag[i]+=x;
}
void down(int i){
if(tag[i]){
if(!L[i])L[i]=++cnt;
if(!R[i])R[i]=++cnt;
lazy(L[i],tag[i]);
lazy(R[i],tag[i]);
tag[i]=0;
}
}
void addd(int tl,int tr,int x,int l,int r,int i){
if(tl<=l&&r<=tr){
lazy(i,x);
}else{
int mid=(l+r)/2;down(i);
if(mid>=tl){
if(!L[i])L[i]=++cnt;
addd(tl,tr,x,l,mid,L[i]);
}
if(mid<tr){
if(!R[i])R[i]=++cnt;
addd(tl,tr,x,mid+1,r,R[i]);
}
up(i);
}
}
void update(int x,int fuck,int l,int r,int i){
if(l==r){
tree[i]=max(tree[i],fuck);
}else{
int mid=(l+r)/2;down(i);
if(x<=mid){
if(!L[i])L[i]=++cnt;
update(x,fuck,l,mid,L[i]);
}else{
if(!R[i])R[i]=++cnt;
update(x,fuck,mid+1,r,R[i]);
}
up(i);
}
}
int query(int tl,int tr,int l,int r,int i){
if(tree[i]==0)return 0;
if(tl<=l&&r<=tr){
return tree[i];
}else{
int mid=(l+r)/2;down(i);
int ans=0;
if(mid>=tl){
ans=max(ans,query(tl,tr,l,mid,L[i]));
}
if(mid<tr){
ans=max(ans,query(tl,tr,mid+1,r,R[i]));
}
return ans;
}
}
void init(){
while(cnt){
tree[cnt]=tag[cnt]=L[cnt]=R[cnt]=0;
cnt--;
}cnt=1;
}
void solve(){
int n;cin>>n;init();
for(int i=1;i<=n;i++){
cin>>l[i]>>r[i];
}
for(int i=1;i<=n;i++){
int val=query(0,l[i]-1,0,1e9,1);
update(l[i],val,0,1e9,1);
addd(l[i],r[i],1,0,1e9,1);
cout<<tree[1]<<" ";
}cout<<endl;
}
signed main(){
#ifdef ONLINE_JUDGE
#else
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
#endif
ios::sync_with_stdio(false);cin.tie(0);
int T;cin>>T;
while(T--){
solve();
}
}

浙公网安备 33010602011771号