极长上升子序列部分变形题总结
T1 God Knows
见识的第一道极长上升子序列题目,当时就傻了
因为题目意思的转化的确恶心的一批
更何况还没见过这类问题
首先要知道这道题求的是极长上升子序列的最小权值
使用线段树维护单调栈,线段树里维护三个东西
站底元素,站内最小值,更改后的站内最小值
实际上是使用了一个叫李超线段树的神奇东西
维护的时候一定注意是要先查询右区间,要不会调死。。。、
详情见我的博客
T2 牛半仙的妹子序列
这是今天的比赛题,不过之前的题解鸽太多就还没写到
这个题是找出极长上升子序列的个数
还是李超线段树,线段书维护单调栈
维护的东西有所改变
站底元素,站内序列个数,修改后站内序列个数
跟之前的T1简直一道题在这里粘贴一波板子,以后当作例题使用就行。。。
1 #include<bits/stdc++.h> 2 #define lid (id<<1) 3 #define rid (id<<1|1) 4 #define int long long 5 using namespace std; 6 const int NN=5e6+5,p=998244353; 7 int n,w[NN],t; 8 struct SNOWtree{ 9 int ll[NN<<2],rr[NN<<2],down[NN<<2],sum[NN<<2],upsum[NN<<2]; 10 void build(int id,int l,int r){ 11 ll[id]=l; rr[id]=r; down[id]=-1; 12 if(l==r) return; int mid=l+r>>1; 13 build(lid,l,mid); build(rid,mid+1,r); 14 } 15 int calc(int id,int it){ 16 if(ll[id]==rr[id]) return down[id]>it?sum[id]:0; 17 if(down[rid]>it) return (upsum[lid]+calc(rid,it))%p; 18 return calc(lid,it); 19 } 20 void update(int id,int pos,int tail,int v){ 21 if(ll[id]==rr[id]){ 22 sum[id]=v; down[id]=tail; 23 return; 24 } 25 if(pos<=rr[lid]) update(lid,pos,tail,v); 26 else update(rid,pos,tail,v); 27 down[id]=max(down[lid],down[rid]); 28 sum[id]=(sum[rid]+(upsum[lid]=calc(lid,down[rid])))%p; 29 } 30 int query(int id,int l,int r){ 31 if(l<=ll[id]&&rr[id]<=r){ 32 int ans=calc(id,t); 33 t=max(down[id],t); 34 return ans; 35 }int ans=0; 36 if(r>=ll[rid]) ans=(ans+query(rid,l,r))%p; 37 if(l<=rr[lid]) ans=(ans+query(lid,l,r))%p; 38 return ans; 39 } 40 }tr; 41 namespace WSN{ 42 inline short main(){ 43 scanf("%lld",&n); 44 for(int i=1;i<=n;i++) scanf("%lld",&w[i]); 45 n++; w[n]=n; tr.build(1,0,n); tr.update(1,0,0,0); 46 for(int i=1;i<=n;i++){ 47 t=-1; 48 int wsn=tr.query(1,0,w[i]-1); 49 if(!wsn) wsn=1; 50 tr.update(1,w[i],i,wsn); 51 if(i==n) printf("%lld\n",wsn); 52 } 53 return 0; 54 } 55 } 56 signed main(){return WSN::main();}

浙公网安备 33010602011771号