[权值线段树][DP]JZOJ 3338 法法塔的奖励
分析
先考虑朴素的做法,就是从1..i-1中权值小于等于wi的f数组中提出最大的转移上来
那么在本题中就是在子树中权值小于等于wi的f数组中提出最大的转移上来
然后权值线段树合并瞎搞即可
#include <iostream> #include <cstdio> #include <algorithm> #include <vector> using namespace std; const int N=1e5+10; struct Graph { int v,nx; }g[N]; int cnt,list[N]; int f[N],root[N],w[N]; int t[40*N],L[40*N],R[40*N],tcnt; int n; int Merge(int x,int y) { if (!x&&!y) return 0; if (!x) return y; if (!y) return x; int T=++tcnt; t[T]=max(t[x],t[y]); L[T]=Merge(L[x],L[y]); R[T]=Merge(R[x],R[y]); return T; } void Insert(int &x,int l,int r,int k,int z) { if (!x) x=++tcnt; if (l==r&&r==k) { t[x]=max(t[x],z); return; } int mid=l+r>>1; if (k<=mid) Insert(L[x],l,mid,k,z); else Insert(R[x],mid+1,r,k,z); t[x]=max(t[L[x]],t[R[x]]); } int Query(int x,int l,int r,int ll,int rr) { if (rr<l||r<ll||r<l) return 0; if (!x) return 0; if (ll<=l&&r<=rr) return t[x]; int mid=l+r>>1,c1=0,c2=0; if (ll<=mid) c1=Query(L[x],l,mid,ll,rr); if (mid<rr) c2=Query(R[x],mid+1,r,ll,rr); return max(c1,c2); } void DFS(int u) { for (int i=list[u];i;i=g[i].nx) { DFS(g[i].v); root[u]=Merge(root[u],root[g[i].v]); } f[u]=Query(root[u],1,n,1,w[u])+1; Insert(root[u],1,n,w[u],f[u]); } int main() { scanf("%d",&n); for (int i=1,f;i<=n;i++) { scanf("%d",&f); if (f>0) g[++cnt]=(Graph){i,list[f]},list[f]=cnt; } for (int i=1;i<=n;i++) scanf("%d",&w[i]); DFS(1); for (int i=1;i<=n;i++) printf("%d ",f[i]); }
在日渐沉没的世界里,我发现了你。