luogu P3780 [SDOI2017]苹果树
题面传送门
首先转化一下题面:一条链可以免费选一次,其余选\(k\)次,选到的最大价值。
因为价值总是\(>0\),因此肯定是选到叶子最优。
然后我们发现这条链上还剩了一些点,这些点看上去可以排序以后贪心,但是\(O(nk)\)再多个log就非常劲爆。
有一种奇技淫巧就是将这些点拆成一个\(1\)与\(a-1\),然后将\(a-1\)挂在\(1\)这个点下面,这样满足依赖关系,并且将剩下的点分到了两边的点。
我们考虑在dfs的时候记录出栈顺序,这样我们可以发现,在一条到叶子的链的左边的点,恰好是叶子在这个序列中左边的点。
树上依赖背包有经典的dfs序方法:如果一个点不选直接跳过一段子树,否则一个一个选。
多重背包的经典优化方法是单调队列,因此我们可以结合单调队列求出一条链左半部分和右半部分的dp值。
然后我们在枚举每个叶子的时候,可以枚举左半边的个数,然后加上这条链的值就可以合并了。
时间复杂度\(O(\sum nk)\)
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (500000+5)
#define M (51000000+5)
#define K (6)
#define mod 1000000007
#define Mod (mod-1)
#define eps (1e-9)
#define ull unsigned ll
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((k+1)*(x)+(y))
#define R(n) (1ll*rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;vector<int> S[N];
int n,k,x,y,z,Dh,A[N],B[N],F1[M],F2[M],Q[N],H,T,D1[N],D2[N],B1[N],B2[N],Si[N],Ans,In[N];
I void dfs1(int x){Si[x]=1;for(int i:S[x]) dfs1(i),Si[x]+=Si[i];D1[B1[x]=++Dh]=x;}
I void dfs2(int x){reverse(S[x].begin(),S[x].end());for(int i:S[x]) dfs2(i);D2[B2[x]=++Dh]=x;reverse(S[x].begin(),S[x].end());}
I void GA(int x,int w){w+=B[x];if(!In[x]&&x<=n)for(int j=0;j<=k;j++)/* cerr<<x<<' '<<w<<' '<<F1[d(B1[x]-1,j)]<<' '<<F2[d(B2[x]-(A[x+n]?2:1),k-j)]<<'\n',*/Ans=max(Ans,w+F1[d(B1[x]-1,j)]+F2[d(B2[x]-(A[x+n]?2:1),k-j)]);for(int i:S[x]) GA(i,w);}
I void Solve(){
int i,j;scanf("%d%d",&n,&k);for(i=1;i<=n;i++) In[i]=0,scanf("%d%d%d",&x,&A[i],&B[i]),A[i+n]=0,A[i]>1&&(A[i+n]=A[i]-1,S[i].PB(i+n),A[i]=1,B[i+n]=B[i]),x&&(S[x].PB(i),In[x]++);
dfs1(1);Dh=0;dfs2(1);for(i=0;i<=k;i++) F1[d(0,i)]=F2[d(0,i)]=0;for(i=1;i<=Dh;i++) {
for(j=0;j<=k;j++) F1[d(i,j)]=F1[d(i-Si[D1[i]],j)];Q[H=T=0]=0;for(j=1;j<=k;j++){
while(H<=T&&Q[H]+A[D1[i]]<j) H++;F1[d(i,j)]=max(F1[d(i,j)],F1[d(i-1,Q[H])]+(j-Q[H])*B[D1[i]]);while(H<=T&&F1[d(i-1,Q[T])]-Q[T]*B[D1[i]]<F1[d(i-1,j)]-B[D1[i]]*j) T--;Q[++T]=j;
}
for(j=0;j<=k;j++) F2[d(i,j)]=F2[d(i-Si[D2[i]],j)];Q[H=T=0]=0;for(j=1;j<=k;j++){
while(H<=T&&Q[H]+A[D2[i]]<j) H++;F2[d(i,j)]=max(F2[d(i,j)],F2[d(i-1,Q[H])]+(j-Q[H])*B[D2[i]]);while(H<=T&&F2[d(i-1,Q[T])]-Q[T]*B[D2[i]]<F2[d(i-1,j)]-B[D2[i]]*j) T--;Q[++T]=j;
}
}Ans=-1e9;GA(1,0);printf("%d\n",Ans);for(i=1;i<=n;i++) S[i].clear();Dh=0;
}
int main(){
freopen("1.in","r",stdin);
int T;scanf("%d",&T);while(T--) Solve();
}```

浙公网安备 33010602011771号