[나무에 다중 가방 의존 DP] BZOJ 4910 [Sdoi 2017] 사과나무.
ai>1의 점은 첫 번째를 먼저 골라서 두 번째를 선택한 것이 틀림없기 때문에 ai>1의 점을 두 개의 점 i′, i′′, i′=1, ai′=ai--1, i′를 i′의 아들로 만들 수 있다.
이 나무에 의존하는 가방은 두 개의 트리의 순서가 반대되는 후순 트리와 대기열 최적화 O (NK) 를 통해 각 점에서 K개를 선택하는 최대 가치를 구할 수 있다.
그리고 각 잎(뜯기 전의 잎)을 일일이 열거하고 두 개의 뒷순서로 옮겨다니는 DP값으로 답을 업데이트하면 된다.
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=40010,K=500010;
bool bg;
int t,n,k,cnt,ncnt,DEPT,iG[N],a[N],v[N],lef[N],dpt[N],sz[N],son[N];
int f[51000010],g[51000010];
int val[N];
ll tot;
struct edge{
int t,nx;
}E[N];
int Ap[N],Bp[N],pa[N],pb[N],A[N],B[N],At,Bt;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void rea(int &x){
char c=nc(); x=0;
for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}
inline void adde(int x,int y){
E[++cnt].t=y; E[cnt].nx=iG[x]; iG[x]=cnt;
}
void dfsf(int x){
Ap[x]=At; sz[x]=1;
for(int i=iG[x];i;i=E[i].nx){
val[E[i].t]=val[x]+v[E[i].t];
dpt[E[i].t]=dpt[x]+1;
dfsf(E[i].t),sz[x]+=sz[E[i].t];
}
A[++At]=x; pa[x]=At;
}
void dfsb(int x){
vector<int> son; Bp[x]=Bt;
for(int i=iG[x];i;i=E[i].nx) son.push_back(E[i].t);
for(int i=son.size()-1;~i;i--) dfsb(son[i]);
B[++Bt]=x; pb[x]=Bt;
}
#define F(x,y) f[(x)*(k+1)+(y)]
#define G(x,y) g[(x)*(k+1)+(y)]
//ll &F(int x,int y){ return f[(x)*(k+1)+(y)]; }
//ll &G(int x,int y){ return g[(x)*(k+1)+(y)]; }
int Q[K],Q1[K],qh,qt;
bool ed;
inline void DP(int *A,int *p,int *f){
for(int i=1;i<=ncnt;i++){
int x=A[i];
int *ff=f+(i-1)*(k+1),*fc=f+i*(k+1);
memcpy(fc,f+p[x]*(k+1),sizeof(int)*(k+1));
//for(int j=0;j<=k;j++) fc[j]=F(p[x],j);
if(a[x]==0) continue;
if(a[x]==1){
for(int j=1;j<=k;j++)
fc[j]=max(fc[j],ff[j-1]+v[x]);
continue;
}
qh=qt=1;
Q[qh]=0; Q1[qh]=0;
for(int j=1;j<=k;j++){
fc[j]=max(fc[j],j*v[x]+Q1[qh]);
while(qh<=qt && Q[qh]<=j-a[x]) qh++;
int cur=ff[j]-j*v[x];
while(qh<=qt && Q1[qt]int ans;
int main(){
rea(t);
while(t--){
rea(n); rea(k);
for(int i=1;i<=n;i++) iG[i]=lef[i]=val[i]=son[i]=0;
//memset(f,0,sizeof(f));
//memset(g,0,sizeof(g));
cnt=0; ncnt=n; At=Bt=0; ans=0; tot=0;
for(int i=1;i<=n;i++){
int p; rea(p); rea(a[i]); rea(v[i]); tot+=a[i];
if(p) adde(p,i),lef[p]=1;
if(a[i]>1)
a[son[i]=++ncnt]=a[i]-1,v[ncnt]=v[i],a[i]=1,adde(i,ncnt),lef[ncnt]=1;
}
val[1]=v[1]; dpt[1]=1;
dfsf(1); dfsb(1);
DP(A,Ap,f);
DP(B,Bp,g);
//printf("%d
",clock()-ttt);
/*for(int i=1;i<=n;i++)
for(int j=0;j<=k;j++)
cout<
for(int i=1;i<=n;i++)
if(!lef[i]){
int cur=min((ll)k,tot-dpt[i]);
int *ff=f+(pa[i]-1)*(k+1),*gg=g+(pb[i]-sz[i])*(k+1);
for(int j=0;j<=cur;j++)
ans=max(ans,ff[j]+gg[cur-j]+val[i]);
}
//printf("%d
",clock()-ttt);
printf("%d
",ans);
}
//printf("%d
",(&ed-&bg)/1024/1024);
return 0;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
[BOJ]11048(python)python 풀이 DP를 이용해 풀이 보통 이런 문제는 dfs나 bfs로 풀이하는 것이여서 고민을 했는데 이 문구 덕분에 DP 를 이용해 풀이할 수 있었다 뒤로 돌아가는 등의 경우를 고려하지 않아도 되기 때문이다 코...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.