1. 程式人生 > >luogu5010 HMR的LIS III (dp+線段樹)

luogu5010 HMR的LIS III (dp+線段樹)

-- 範圍 turn cond char || pac 開頭 離散化

這個東西和最長上升子序列很像

考慮如果已經知道每個位置為開頭的LIS長度和個數 f[i],我可以掃一遍 判斷這個個數和K的大小,找到第一個長度=len而且個數<K的,這個位置就是要選的 然後K-=個數,len--,再記下來我這次選的是這個位置(以後還要判斷當前位置是否在上一個欽定住的範圍內),然後接著做

那這玩意怎麽求呢,離散化一下 算出每個數能跳到的下一個數的大小的區間 倒著dp 用線段樹記以這個權值為開頭的最大長度和個數 優化轉移就可以了

 1 #include<bits/stdc++.h>
 2 #define CLR(a,x) memset(a,x,sizeof(a))
 3
using namespace std; 4 typedef long long ll; 5 typedef pair<int,ll> pa; 6 const int maxn=5e5+10; 7 8 inline ll rd(){ 9 ll x=0;char c=getchar();int neg=1; 10 while(c<0||c>9){if(c==-) neg=-1;c=getchar();} 11 while(c>=0&&c<=9) x=x*10+c-0,c=getchar();
12 return x*neg; 13 } 14 15 int N,M,Llim,Rlim,L[maxn],R[maxn],a[maxn],tmp[maxn]; 16 int ans[maxn]; 17 ll K; 18 pa ma[maxn<<2],f[maxn]; 19 20 inline void merge(pa &a,pa b){ 21 if(a.first<b.first) a=b; 22 else if(a.first==b.first){ 23 a.second+=b.second; 24
a.second=min(a.second,(ll)1e13+1); 25 } 26 } 27 28 inline void update(int p){ 29 ma[p]=make_pair(0,0); 30 merge(ma[p],ma[p<<1]);merge(ma[p],ma[p<<1|1]); 31 } 32 33 inline void change(int p,int l,int r,int x,pa y){ 34 if(l==r){ 35 merge(ma[p],y); 36 }else{ 37 int m=l+r>>1; 38 if(x<=m) change(p<<1,l,m,x,y); 39 else change(p<<1|1,m+1,r,x,y); 40 update(p); 41 } 42 } 43 44 inline void query(int p,int l,int r,int x,int y,pa &z){ 45 if(x>y||x>M) return; 46 y=min(y,M); 47 if(x<=l&&r<=y) merge(z,ma[p]); 48 else{ 49 int m=l+r>>1; 50 if(x<=m) query(p<<1,l,m,x,y,z); 51 if(y>=m+1) query(p<<1|1,m+1,r,x,y,z); 52 } 53 } 54 55 int main(){ 56 //freopen("","r",stdin); 57 int i,j,k; 58 N=rd(),K=rd(),Llim=rd(),Rlim=rd(); 59 for(i=1;i<=N;i++) 60 a[i]=tmp[i]=rd(); 61 sort(tmp+1,tmp+N+1);M=unique(tmp+1,tmp+N+1)-tmp-1; 62 for(i=1;i<=N;i++){ 63 L[i]=upper_bound(tmp+1,tmp+M+1,a[i]+Llim)-tmp; 64 R[i]=lower_bound(tmp+1,tmp+M+1,a[i]+Rlim)-tmp-1; 65 a[i]=lower_bound(tmp+1,tmp+M+1,a[i])-tmp; 66 // printf("~%d %d %d %d\n",i,a[i],L[i],R[i]); 67 } 68 for(i=N;i;i--){ 69 pa re=make_pair(0,0); 70 query(1,1,M,L[i],R[i],re); 71 if(re.first>=1) f[i]=make_pair(re.first+1,re.second); 72 else f[i]=make_pair(1,1); 73 change(1,1,M,a[i],f[i]); 74 // printf("%d %d %d %d %d %d %d\n",i,L[i],R[i],f[i].first,f[i].second,re.first,re.second); 75 } 76 int len=0; 77 for(i=1;i<=N;i++) 78 len=max(len,f[i].first); 79 printf("%d\n",len); 80 int lst=-1; 81 for(i=1,j=0;i<=N;i++){ 82 if(f[i].first!=len||(lst!=-1&&(a[i]>R[lst]||a[i]<L[lst]))) continue; 83 if(f[i].second<K) K-=f[i].second; 84 else ans[++j]=i,len--,lst=i; 85 } 86 for(i=1;i<=j;i++) 87 printf("%d ",ans[i]); 88 return 0; 89 }

luogu5010 HMR的LIS III (dp+線段樹)