引自:wonter巨巨的博客
定义 dp[i] := 以数字 i(不是下标 i)为结尾的最长上升长度
然后用线段树维护 dp[i]:每个节点维护 2 个信息,一个是当前区间的最大上升长度,一个是最大上升长度的方案数,
这里再详细说下这篇题解。。。也是弱弱自己的理解吧。。。
以1-n的值为线段树所代表的区间;
然后依次更新,题目就是要找上升序列,那么我们只要每次查询0~arr[i]-1范围内最长的那个长度和方案拿出来;
然后再去0到n区间里更新,更新的值是arr[i],长度为查询到的x+1,方案还是查询到的方案y;
具体查询:
我们是想知道在一段区间(从0到值arr[i]-1,这里一定要注意是值!是值!)的最长长度;
所以一直查询到那个区间,然后一直下去就好了;中间如果出现被mid是夹在被查询区间中间的话,就要比较一下左右两段区间的最长长度
具体更新:
一直要先更新到最底;
然后再往上更新,
往上更新只要比较一下左右子区间的长度就好了;
#include <bits/stdc++.h> using namespace std; const int N=5e5+10; const int mod=1e9+7; struct asd{ int left,right,mid; int val; int cnt; }; asd q[N*4]; void build(int i,int left,int right) { q[i].left=left; q[i].right=right; q[i].mid=(left+right)>>1; q[i].cnt=q[i].val=0; if(left==right) return; build(i*2,left,q[i].mid); build(i*2+1,q[i].mid+1,right); } void query(int i, int left, int right, int &x, int &y ) { if(q[i].left==left&&q[i].right==right) { x=q[i].val; y=q[i].cnt; return; } if(right<=q[i].mid) { query(i*2, left, right, x, y); return; } if(left>q[i].mid) { query(i*2+1,left,right, x, y); return; } int lx,ly; int rx,ry; query(i*2,left,q[i].mid,lx,ly); query(i*2+1,q[i].mid+1,right, rx,ry); if(lx==rx) { x=lx; y=(ly+ry)%mod; } else if(lx>rx) { x=lx; y=ly; } else { x=rx; y=ry; } } void update(int i,int p,int x,int y) { if(q[i].left==q[i].right&&q[i].left==p) { if(x>q[i].val) { q[i].val=x; q[i].cnt=y; } else if(x==q[i].val) { q[i].cnt=(q[i].cnt+y)%mod; } return; } if(p<=q[i].mid) update(i*2,p,x,y); else if(p>q[i].mid) update(i*2+1,p,x,y); if(q[i*2].val==q[i*2+1].val) { q[i].val=q[i*2].val; q[i].cnt=(q[i*2].cnt+q[i*2+1].cnt)%mod; } else if(q[i*2].val>q[i*2+1].val) { q[i].val=q[i*2].val; q[i].cnt=q[i*2].cnt; } else { q[i].val=q[i*2+1].val; q[i].cnt=q[i*2+1].cnt; } } int n; int arr[N]; vector<int>xs; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&arr[i]); xs.push_back(arr[i]); } sort(xs.begin(),xs.end()); auto e=unique(xs.begin(),xs.end()); for(int i=1;i<=n;i++) arr[i]=lower_bound(xs.begin(), e, arr[i])-xs.begin()+1; build(1,0,n); for(int i=1;i<=n;i++) { int x,y; query(1,0,arr[i]-1,x,y); // printf("%d %d ",x,y); if(!y) y=1; update(1, arr[i] , x+1, y); } int x,y; query(1,0,n,x,y); printf("%d ",y); return 0; }