正题
题目链接:https://www.luogu.com.cn/problem/CF809D
正题
题目链接:https://www.luogu.com.cn/problem/CF809D
题目大意
有一个长度为nnn的序列aaa,要求ai∈[li,ri]a_i\in[l_i,r_i]ai∈[li,ri],要求使得aaa的最长严格上升子序列最长。
1≤n≤3×105,1≤li≤ri≤1091\leq n\leq 3\times 10^5,1\leq l_i\leq r_i\leq 10^91≤n≤3×105,1≤li≤ri≤109
解题思路
考虑一下暴力的做法,我们设fif_ifi表示在目前的序列中后面加个数字iii为结尾时的最长上升子序列,那么显然fff是单调不降的。
同理由于是严格上升,所以我们fff不可能一次升222的值,也就是fi≤fi−1+1f_i\leq f_{i-1}+1fi≤fi−1+1。所以我们可以考虑维护fi=fi−1+1f_i=f_{i-1}+1fi=fi−1+1的位置,也就是维护fff的差分数组中的111的位置。
考虑新加入一个[l,r][l,r][l,r]时的变化,那对于所有i∈[l+1,r+1]i\in[l+1,r+1]i∈[l+1,r+1]都有fi=max{fi,fj+1}(j<i)f_i=max\{f_i,f_j+1\}(j<i)fi=max{fi,fj+1}(j<i),注意到111位置的变化我们可以得出一下结论,当修改[l,r][l,r][l,r]时需要
- 将[l+1,r][l+1,r][l+1,r]中所有111的后面那个111移动到这个111的后一位。
- 将[l+1,r][l+1,r][l+1,r]中的第一个111移动到l+1l+1l+1处
这个操作看起来很难实现,实际上我们可以将第一个视为将[l+1,r+1][l+1,r+1][l+1,r+1]中的111往后移一格。
我们用FhqTreap维护111的位置,然后把(r,∞)(r,\infty)(r,∞)中第一个111删除,[l+1,r][l+1,r][l+1,r]中的所有111往后移一格,再在l+1l+1l+1这个位置插一个111就好了。
时间复杂度:O(nlogn)O(n\log n)O(nlogn)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=3e5+10;
int n,cnt,rt,w[N],dat[N],lazy[N],siz[N],t[N][2];
void Downdata(int x){if(!lazy[x])return;for(int i=0;i<2;i++){if(!t[x][i])continue;lazy[t[x][i]]+=lazy[x];w[t[x][i]]+=lazy[x];}lazy[x]=0;return;
}
int NewNode(int val){siz[++cnt]=1;dat[cnt]=rand();w[cnt]=val;return cnt;
}
void PushUp(int x){siz[x]=siz[t[x][0]]+siz[t[x][1]]+1;return;
}
void Split(int &x,int &y,int p,int k){if(!p){x=y=0;return;}Downdata(p);if(w[p]<=k)x=p,Split(t[x][1],y,t[p][1],k);else y=p,Split(x,t[y][0],t[p][0],k);PushUp(p);return;
}
int Merge(int x,int y){Downdata(x);Downdata(y);if(!x||!y)return x|y;if(dat[x]<dat[y]){t[x][1]=Merge(t[x][1],y);PushUp(x);return x;}else{t[y][0]=Merge(x,t[y][0]);PushUp(y);return y;}return x|y;
}
int Findk(int x,int k){if(siz[t[x][0]]>=k)return Findk(t[x][0],k);if(siz[t[x][0]]+1==k)return x;return Findk(t[x][1],k-siz[t[x][0]]-1);
}
int main()
{
// freopen("vague.in","r",stdin);
// freopen("vague.out","w",stdout);srand(19260817);scanf("%d",&n);for(int i=1,l,r;i<=n;i++){scanf("%d%d",&l,&r);int x,y,z;l++;Split(x,y,rt,l-1);Split(y,z,y,r);if(z){int v=w[Findk(z,1)],nu;Split(nu,z,z,v);}if(y)lazy[y]++,w[y]++;y=Merge(NewNode(l),y);y=Merge(y,z);rt=Merge(x,y);}printf("%d\n",siz[rt]);return 0;
}