【BZOJ5469】[FJOI2018]領導集團問題(動態規劃,線段樹合並)
阿新 • • 發佈:2019-02-27
狀態 space 位置 ret max flag 得到 modify 線段樹合並
考慮對於後綴進行差分,每次相當於現在\(w[i]\)位置加一,然後往前更新一段,直到下一個差分數組上有\(1\)的位置。
那麽用線段樹合並就可以解決這個問題,給\(w[i]\)位置加一,然後線段樹上二分找到上一個為\(1\)的位置然後把它減一就好了。
【BZOJ5469】[FJOI2018]領導集團問題(動態規劃,線段樹合並)
題面
BZOJ
洛谷
題解
題目就是讓你在樹上找一個最大的點集,使得兩個點如果存在祖先關系,那麽就要滿足祖先的權值要小於等於兒子的權值。
首先離散權值。
考慮一個暴力\(dp\),設\(f[i][j]\)表示以\(i\)為根,子樹中被選擇的最小值為\(j\)時能夠被選出的最大點樹。然後xjb轉移一下就寫出了一個\(O(n^3)\)的優秀做法。
然後把狀態從恰好變成至少,然後就得到了一個\(O(n^2)\)的做法。
考慮\(O(n^2)\)的\(dp\),本質上就是在維護一個後綴的最大值。
不難發現後綴最大值一定是不降的。
那麽用線段樹合並就可以解決這個問題,給\(w[i]\)位置加一,然後線段樹上二分找到上一個為\(1\)的位置然後把它減一就好了。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define MAX 200200 inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } struct Line{int v,next;}e[MAX<<1]; int h[MAX],cnt=1; inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;} int n,ans,w[MAX],S[MAX],tot,rt[MAX]; int ls[MAX*18],rs[MAX*18],t[MAX*18],node; void Modify(int &x,int l,int r,int p) { if(!x)x=++node;t[x]+=1;if(l==r)return; int mid=(l+r)>>1; if(p<=mid)Modify(ls[x],l,mid,p); else Modify(rs[x],mid+1,r,p); } bool Flag; void Calc(int x) { if(!x)return;t[x]-=1; if(t[rs[x]])Calc(rs[x]); else Calc(ls[x]); } void Minus(int x,int l,int r,int p) { if(l==r)return;int mid=(l+r)>>1; if(p<=mid)Minus(ls[x],l,mid,p); else { Minus(rs[x],mid+1,r,p); if(!Flag&&t[ls[x]])Flag=true,Calc(ls[x]); } if(Flag)t[x]-=1; } void Merge(int &x,int &y) { if(!x||!y){x|=y;return;}t[x]+=t[y]; Merge(ls[x],ls[y]);Merge(rs[x],rs[y]); } void dfs(int u) { for(int i=h[u];i;i=e[i].next) dfs(e[i].v),Merge(rt[u],rt[e[i].v]); Modify(rt[u],1,tot,w[u]); Flag=false;Minus(rt[u],1,tot,w[u]); } int main() { n=read(); for(int i=1;i<=n;++i)S[++tot]=w[i]=read(); for(int i=2;i<=n;++i)Add(read(),i); S[++tot]=1e9+1;sort(&S[1],&S[tot+1]);tot=unique(&S[1],&S[tot+1])-S-1; for(int i=1;i<=n;++i)w[i]=lower_bound(&S[1],&S[tot+1],w[i])-S; dfs(1);printf("%d\n",t[rt[1]]); return 0; }
【BZOJ5469】[FJOI2018]領導集團問題(動態規劃,線段樹合並)