[DP][二分]JZOJ 3467 最长上升子序列
分析
我们可以容易发现这个题的数据输入呈一个树形,但是我们无法每次都对一条链求最长上升子序列。
然后想到DFS可以重置一些东西,记录一些相关的变化量再退回即可。
(然后传统DFS居然爆栈了?)手写一个while版的DFS= =
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int N=500001; struct Edge { int u,v,nx; }g[N]; struct D { int j,k,u,v; bool b; }stk[N]; int top; int cnt,list[N]; int f[N],d[N],num[N],w[N]; int pcnt,mlen; int n; void Add(int u,int v) { g[++cnt].u=u;g[cnt].v=v;g[cnt].nx=list[u];list[u]=cnt; } void Dfs(int u) { stk[top].u=u; while (1) { while (!list[stk[top].u]&&top>0) { top--; if (stk[top].b) d[mlen--]=0; else if (stk[top].j>0) d[stk[top].j]=stk[top].k; }; if (!list[stk[top].u]) break; int i=list[stk[top].u]; list[stk[top].u]=g[i].nx; stk[top].v=g[i].v; stk[top].b=0; if (d[mlen]<w[stk[top].v]) { d[++mlen]=w[stk[top].v]; stk[top].b=1; } else { stk[top].j=lower_bound(d,d+mlen+1,w[stk[top].v])-d; if (stk[top].j>0) stk[top].k=d[stk[top].j],d[stk[top].j]=w[stk[top].v]; } f[stk[top].v]=mlen; top++; stk[top].u=stk[top-1].v; } } void Init() { scanf("%d",&n); num[0]=0; for (int i=1;i<=n;i++) { int order,p; scanf("%d%d",&order,&p); if (order) num[i]=num[p]; else { num[i]=++pcnt; Add(num[i-1],num[i]); w[pcnt]=p; } } d[0]=-2147483647;mlen=0; } void Print() { for (int i=1;i<=n;i++) printf("%d\n",f[num[i]]); } int main() { freopen("lis.in","r",stdin); freopen("lis.out","w",stdout); Init(); Dfs(0); Print(); fclose(stdin);fclose(stdout); }
在日渐沉没的世界里,我发现了你。