jzoj5336-[NOIP2017提高A組模擬8.24]提米樹【dp】
阿新 • • 發佈:2021-07-21
正題
題目連結:https://gmoj.net/senior/#main/show/5336
題目大意
\(n\)個點的一棵樹,選擇一些節點作為葉子(割掉它的所有子節點)。
然後要求葉子的權值和減去相鄰葉子路徑之間(不算頭尾)最大權值最大。
\(1\leq n\leq 10^5\)
解題思路
有一個很簡單的\(O(n^2)dp\)就是設上一個葉子是\(f_x\)。
然後考慮優化,相鄰葉子之間的路徑長度是小於\(2n\)的所以可以考慮處理這個東西。
我們用\(LCA\)到左邊葉子的路徑來更新到右邊葉子路徑上的\(f\)值,記\(mx_x\)表示\(LCA\)到\(x\)節點的路徑最大權值,考慮到轉移式子中有一個\(max\{mx_l,mx_r\}\)
時間複雜度\(O(n)\)
code
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int N=2e5+10; int n,k,cnt,tot,lf[N],w[N],fa[N],dep[N],dfn[N],rfn[N]; int f[N],mx[N],mf[N],mg[N],ans ;vector<int> G[N]; void dfs(int x){ dep[x]=dep[fa[x]]+1; dfn[++cnt]=x;rfn[x]=cnt; for(int i=0;i<G[x].size();i++){ int y=G[x][i]; if(y==fa[x])continue; fa[y]=x;dfs(y); dfn[++cnt]=x; } if(G[x].empty())lf[++tot]=x; return; } int main() { scanf("%d",&n); for(int i=1,k;i<=n;i++){ scanf("%d%d",&w[i],&k); for(int j=1;j<=k;j++){ int x;scanf("%d",&x); G[i].push_back(x); } } dfs(1); for(int i=1;i<=rfn[lf[1]];i++)f[dfn[i]]=w[dfn[i]]; for(int p=2;p<=tot;p++){ int l=rfn[lf[p-1]],r=rfn[lf[p]],mid=l; for(int i=l+1;i<=r;i++) if(dep[dfn[i]]<dep[dfn[mid]])mid=i; mx[mid]=w[dfn[mid]];mf[mid-1]=f[dfn[mid-1]]; for(int i=mid-1;i>=l;i--)mx[i]=max(mx[i+1],w[dfn[i+1]]); for(int i=mid+1;i<=r;i++)mx[i]=max(mx[i-1],w[dfn[i-1]]); for(int i=mid-2;i>=l;i--)mf[i]=max(mf[i+1],f[dfn[i]]); mg[l]=f[dfn[l]]-mx[l]; for(int i=l+1;i<mid;i++)mg[i]=max(mg[i-1],f[dfn[i]]-mx[i]); //R.I.P for(int i=mid+1,j=mid-1;i<=r;i++){ f[dfn[i]]=-1e9-7; while(j>=l&&mx[i]>=mx[j])j--; if(j<mid-1)f[dfn[i]]=mf[j+1]-mx[i]; if(j>=l)f[dfn[i]]=max(f[dfn[i]],mg[j]); f[dfn[i]]+=w[dfn[i]]; } //R.I.P } for(int i=rfn[lf[tot]];i<=cnt;i++)ans=max(ans,f[dfn[i]]); printf("%d\n",ans); return 0; } //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P //R.I.P