日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

sdoi2017苹果树

發布時間:2023/12/14 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 sdoi2017苹果树 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題解:

非常奇妙的一題。。

沒有免費操作我都不會$nk$。。。。考試打個暴力就可以走人了

樹上有依賴背包問題的正確做法是(為啥我之前學的不是這樣的啊)

按照后續遍歷做背包

做到一個點的時候 枚舉它選不選 不選只能從子樹外轉移 選的話可以從x-1轉移

而不是對每個點求一次$f[i][j]$ 這樣是$n*k^2$

前者不管是多重背包還是0/1背包 復雜度都是$nk$的(單調隊列優化)

將題目給的條件轉化,變成有一條鏈是免費

我們會發現這樣求出的路徑是它到根的路徑的左邊和自己子樹的背包

那么我們可以想到 如果按照右左根再遍歷一遍 可以得到右邊+自己子樹的背包

另外有一個性質就是,這條鏈一定會到葉子

而我們發現對于葉子兩個背包合并的話就只多算了當前點并且當前點到根這一段都沒有算(只要把一個編號右移一位就沒有重復了)

這恰好符合了題目的免費操作

但是注意那些點ai是可以>1也就是說還需要考慮付費部分

一種直觀的思路是對其中一種dfs子兒子之前先把$(ai-1,vi)$作為一種物品放進去

其實這等價于再加一個$(ai-1,vi)$的兒子

然后這樣就可以卡著空間過了。。 因為多加了兒子,數組需要2.5e7*2*2

***常數巨大但洛谷評測機快就過了

單調隊列里面一堆變量寫錯。。

數組大小一堆開錯。。然后查錯查了一個小時。。

代碼:

#include <bits/stdc++.h> using namespace std; #define rint register int #define IL inline #define rep(i,h,t) for(int i=h;i<=t;i++) #define dep(i,t,h) for(int i=t;i>=h;i--) #define ll long long #define me(x) memset(x,0,sizeof(x)) #define mep(x,y) memcpy(x,y,sizeof(y)) #define mid (t<=0?(h+t-1)/2:(h+t)/2) namespace IO{char ss[1<<24],*A=ss,*B=ss;IL char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;}template<class T> void read(T &x){rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f; }char sr[1<<24],z[20]; int Z,C1=-1;template<class T>void wer(T x){if (x<0) sr[++C1]='-',x=-x;while (z[++Z]=x%10+48,x/=10);while (sr[++C1]=z[Z],--Z);}IL void wer1(){sr[++C1]=' ';}IL void wer2(){sr[++C1]='\n';}template<class T>IL void maxa(T &x,T y) {if (x<y) x=y;}template<class T>IL void mina(T &x,T y) {if (x>y) x=y;} template<class T>IL T MAX(T x,T y){return x>y?x:y;}template<class T>IL T MIN(T x,T y){return x<y?x:y;} }; using namespace IO; const int N=6e5; const int N2=51000000; int n,k,ans[N],a[N],v[N],dp1[N2],dp2[N2],sum[N],cnt; int dfn1[N],dfn2[N]; vector<int> ve[N]; struct re{int a,b; }p[N]; void dfs1(int x) {sum[x]=1;for (int i=0;i<ve[x].size();i++){ans[ve[x][i]]=ans[x]+v[x];dfs1(ve[x][i]);sum[x]+=sum[ve[x][i]];}dfn1[x]=++cnt;int n1=dfn1[x]-1,k1=n1*(k+1);int k2=dfn1[x]*(k+1);int h=1,t=0; p[1]=(re){0,0};rep(i,0,k){if (h<=t&&(i-p[h].a)>a[x]) h++;if (h<=t) dp1[k2+i]=v[x]*i+p[h].b;int now=dp1[k1+i]-v[x]*i;while (h<=t&&now>=p[h].b) t--;p[++t]=(re){i,now};}n1=dfn1[x]-sum[x],k1=n1*(k+1);rep(i,0,k){ dp1[k2+i]=MAX(dp1[k2+i],dp1[k1+i]);if (i) maxa(dp1[k2+i],dp1[k2+i-1]);} } bool vis[N]; void dfs2(int x) {vis[x]=1;sum[x]=1;for (int i=(int)(ve[x].size())-1;i>=0;i--){dfs2(ve[x][i]);sum[x]+=sum[ve[x][i]];}dfn2[x]=++cnt;int n1=dfn2[x]-1,k1=n1*(k+1);int k2=dfn2[x]*(k+1);int h=1,t=0; p[1]=(re){0,0};rep(i,0,k){if (h<=t&&(i-p[h].a)>a[x]) h++;if (h<=t) dp2[k2+i]=v[x]*i+p[h].b;int now=dp2[k1+i]-v[x]*i;while (h<=t&&now>=p[h].b) t--;p[++t]=(re){i,now};}n1=dfn2[x]-sum[x],k1=n1*(k+1);rep(i,0,k){ dp2[k2+i]=MAX(dp2[k2+i],dp2[k1+i]);if (i) maxa(dp2[k2+i],dp2[k2+i-1]);} } int main() {freopen("1.in","r",stdin);freopen("1.out","w",stdout);int T;read(T);rep(ttt,1,T){read(n); read(k); me(dp1); me(dp2);rep(i,0,N-1){vector<int> v2;v2.swap(ve[i]);}rep(i,1,n) {int x; read(x);read(a[i]); read(v[i]);if (x) ve[x].push_back(i);a[i+n]=a[i]-1,v[i+n]=v[i];a[i]=1;ve[i].push_back(i+n);}cnt=0; dfs1(1);cnt=0; dfs2(1);int num=0;rep(i,n+1,2*n)rep(j,0,k) maxa(num,ans[i]+dp1[dfn1[i]*(k+1)+j]+dp2[(dfn2[i]-1)*(k+1)+k-j]);cout<<num<<endl;}return 0; }

?

轉載于:https://www.cnblogs.com/yinwuxiao/p/10057559.html

總結

以上是生活随笔為你收集整理的sdoi2017苹果树的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。