题意:n点m边,然后要求走最多的路,走路的时候经过的边权必须是严格递增。
解法1:传统的区间更新
解法2:发现区间更新只是对两个固定的点所延长形成的区间段,所以问题可以退化成单点更新单点查询。
然后动态开辟线段树就行了
线段树有1e5个然后每个都是权值线段树
解法一所需要的空间会比解法二大很多很多,甚至一度以为我写错了.....
#include<cstdio> #include<vector> #include<cstring> #include<algorithm> using namespace std; const int N=2e5+88; int rt[N],L[N*25],R[N*25],V[N*25],lz[N*25]; int n,m,tot; void update(int &k,int pos,int l,int r,int y){ if(!k) k=++tot; if(l>=pos) { V[k]=max(y,V[k]); lz[k]=max(y,lz[k]); return; } if(lz[k]) { if(!L[k]) L[k]=++tot;if(!R[k]) R[k]=++tot; lz[L[k]]=max(lz[L[k]],lz[k]); lz[R[k]]=max(lz[k],lz[R[k]]); V[L[k]]=max(V[L[k]],lz[k]); V[R[k]]=max(V[R[k]],lz[k]); lz[k]=0; } int m=(l+r)>>1; if(pos<=m) update(L[k],pos,l,m,y); update(R[k],pos,m+1,r,y); V[k]=max(V[L[k]],V[R[k]]); } int query(int l,int r,int w,int k){ if(!k) return 0; if(r<=w) return V[k]; int m=(l+r)>>1; if(lz[k]) { if(!L[k]) L[k]=++tot;if(!R[k]) R[k]=++tot; lz[L[k]]=max(lz[L[k]],lz[k]); lz[R[k]]=max(lz[k],lz[R[k]]); V[L[k]]=max(V[L[k]],lz[k]); V[R[k]]=max(V[R[k]],lz[k]); lz[k]=0; } int ans=query(l,m,w,L[k]); if(w>m) ans=max(ans,query(m+1,r,w,R[k])); return ans; } int main(){ scanf("%d%d",&n,&m); int x,y,z,ans=0; for(int i=1;i<=m;++i) { scanf("%d%d%d",&x,&y,&z); z+=10; int Q=query(1,100020,z-1,rt[x])+1; ans=max(ans,Q); update(rt[y],z,1,100020,Q); } printf("%d ",ans); }
#include<cstdio> #include<vector> #include<cstring> #include<algorithm> using namespace std; const int N=1e5+88; int rt[N],L[N*20],R[N*20],V[N*20]; int n,m,tot; void update(int &k,int pos,int l,int r,int y){ if(!k) k=++tot; V[k]=max(V[k],y); if(l==r) return; int m=(l+r)>>1; if(pos<=m) update(L[k],pos,l,m,y); else update(R[k],pos,m+1,r,y); } int query(int l,int r,int w,int k){ if(!k) return 0; if(l==r) return V[k]; int m=(l+r)>>1; if(w<=m) return query(l,m,w,L[k]); else return max(V[L[k]],query(m+1,r,w,R[k])); } int main(){ scanf("%d%d",&n,&m); int x,y,z,ans=0; for(int i=1;i<=m;++i) { scanf("%d%d%d",&x,&y,&z); z+=10; int Q=query(1,100020,z-1,rt[x])+1; ans=max(ans,Q); update(rt[y],z,1,100020,Q); } printf("%d ",ans); }