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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

[Apio2012]dispatching 主席树做法

發(fā)布時間:2025/4/16 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [Apio2012]dispatching 主席树做法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

bzoj 2809: [Apio2012]dispatching

http://www.lydsy.com/JudgeOnline/problem.php?id=2809

Description

在一個忍者的幫派里,一些忍者們被選中派遣給顧客,然后依據(jù)自己的工作獲取報償。在這個幫派里,有一名忍者被稱之為?Master。除了?Master以外,每名忍者都有且僅有一個上級。為保密,同時增強忍者們的領導力,所有與他們工作相關的指令總是由上級發(fā)送給他的直接下屬,而不允許通過其他的方式發(fā)送。現(xiàn)在你要招募一批忍者,并把它們派遣給顧客。你需要為每個被派遣的忍者 支付一定的薪水,同時使得支付的薪水總額不超過你的預算。另外,為了發(fā)送指令,你需要選擇一名忍者作為管理者,要求這個管理者可以向所有被派遣的忍者 發(fā)送指令,在發(fā)送指令時,任何忍者(不管是否被派遣)都可以作為消息的傳遞 人。管理者自己可以被派遣,也可以不被派遣。當然,如果管理者沒有被排遣,就不需要支付管理者的薪水。你的目標是在預算內使顧客的滿意度最大。這里定義顧客的滿意度為派遣的忍者總數(shù)乘以管理者的領導力水平,其中每個忍者的領導力水平也是一定的。寫一個程序,給定每一個忍者?i的上級?Bi,薪水Ci,領導力L i,以及支付給忍者們的薪水總預算?M,輸出在預算內滿足上述要求時顧客滿意度的最大值。 1??≤N?≤ 100,000?忍者的個數(shù); 1??≤M?≤ 1,000,000,000?薪水總預算;? 0??≤Bi < i??忍者的上級的編號; 1??≤Ci ≤ M?????????????????????忍者的薪水; 1??≤Li ≤ 1,000,000,000?????????????忍者的領導力水平。

Input

從標準輸入讀入數(shù)據(jù)。 第一行包含兩個整數(shù)?N和?M,其中?N表示忍者的個數(shù),M表示薪水的總預算。 接下來?N行描述忍者們的上級、薪水以及領導力。其中的第?i?行包含三個整?Bi , C i , L i分別表示第i個忍者的上級,薪水以及領導力。Master滿足B i = 0,并且每一個忍者的老板的編號一定小于自己的編號?Bi < i。

Output

輸出一個數(shù),表示在預算內顧客的滿意度的最大值。

Sample Input

5 4
0 3 3
1 3 5
2 2 2
1 2 4
2 3 1

Sample Output

6

HINT

如果我們選擇編號為 1的忍者作為管理者并且派遣第三個和第四個忍者,薪水總和為 4,沒有超過總預算。

因為派遣了2 個忍者并且管理者的領導力為 3,用戶的滿意度為 6 ?,是可以得到的用戶滿意度的最大值。

題目剖析:

ans=領導力*個數(shù)

領導力:枚舉每個忍者

個數(shù):當然是需要薪水少的先派遣啦

所以,節(jié)點的領導力為a,在以這個節(jié)點為根的子樹中(包括這個節(jié)點),從小到大選盡可能多的節(jié)點s,滿足節(jié)點的薪水和<=總預算,最大化a*s

這道題還可以用左偏樹來做,但蒟蒻一枚只會主席樹 ,所以這里只寫主席樹做法

推薦黃學長的博客,維護子樹大根堆,用可并堆將時間復雜度降為nlongn ?http://hzwer.com/5682.html

數(shù)據(jù)結構:主席樹

輔助:dfs序(開始沒想到)

以忍者的dfs序為下標,薪水為區(qū)間建立主席樹

首先說說dfs序

1、為什么需要dfs序?

因為派遣忍者的范圍是以這個忍者為根的子樹。

假設當前節(jié)點為i,遍歷到時令 in[i]=a, 表示i是第a個被遍歷。以i為節(jié)點的子樹遍歷完后,令out[i]=b,b為當前所有已遍歷節(jié)點總數(shù)

那么這個節(jié)點可以派遣的范圍是dfs序[a,b](包括a,b)之間的忍者

所dfs序的作用是鎖定查找區(qū)間

2、如何構造dfs序?(自己也沒想到)

令t表示當前已遍歷節(jié)點總數(shù),每遍歷一個節(jié)點t++,設當前節(jié)點為i,遍歷到i是in[i]=t,i退出時out[i]=t

在構造dfs序時,順便記錄下dfs序為i的忍者的薪水、領導力,然后按照dfs序在主席樹中插入節(jié)點

最后是查找

枚舉每個忍者,查找他的派遣范圍最多能派遣多少個忍者

如果做過[CQOI2015]任務查詢系統(tǒng),會知道那道題在查詢查到葉子節(jié)點時,對答案的貢獻是sum[l]/count[l]*k

本題查詢的是數(shù)量,到葉子節(jié)點時有沒有坑呢?

有。葉子節(jié)點對答案有貢獻的忍者數(shù)量應該是 min(薪水預算/派遣這個節(jié)點的忍者所需薪水,這個節(jié)點的忍者個數(shù))

這里的節(jié)點是主席樹中以薪水為區(qū)間建立的節(jié)點

還有就是要注意答案用long long

#include<cstdio> #include<algorithm> #define N 100001 using namespace std; int n,m,money[N],lead[N],front[N],next[N]; int hash[N],cnt_money; int in[N],out[N],t; int root[N],tot,lc[N*20],rc[N*20],cnt[N*20]; long long sum[N*20],ans,dispatch; struct node {int mon,lea; }e[N]; inline void add(int u,int v) {next[v]=front[u];front[u]=v; } inline int dfs(int r) {in[r]=++t;e[t].lea=lead[r];e[t].mon=hash[r];if(front[r])for(int i=front[r];i;i=next[i])dfs(i);out[r]=t; } void discrete() {sort(money+1,money+n+1); cnt_money=unique(money+1,money+n+1)-(money+1);for(int i=1;i<=n;i++) hash[i]=lower_bound(money+1,money+cnt_money+1,hash[i])-money; } inline void insert(int pre,int & now,int l,int r,int w) {sum[now=++tot]=sum[pre]+money[w];cnt[now]=cnt[pre]+1;if(l==r) return;int mid=l+r>>1;if(w<=mid){rc[now]=rc[pre];insert(lc[pre],lc[now],l,mid,w);}else{lc[now]=lc[pre];insert(rc[pre],rc[now],mid+1,r,w);} } inline int query(int x,int y,int l,int r,long long k) {if(l==r) return min(k/(long long)money[l],(long long)(cnt[y]-cnt[x]));int mid=l+r>>1;long long tmp=sum[lc[y]]-sum[lc[x]];if(k<=tmp) return query(lc[x],lc[y],l,mid,k);else return cnt[lc[y]]-cnt[lc[x]]+query(rc[x],rc[y],mid+1,r,k-tmp); } int main() {scanf("%d%lld",&n,&m);int b,c,l;for(int i=1;i<=n;i++){scanf("%d%d%d",&b,&money[i],&lead[i]);hash[i]=money[i];add(b,i);}discrete();dfs(front[0]);for(int i=1;i<=n;i++) insert(root[i-1],root[i],1,cnt_money,e[i].mon); for(int i=1;i<=n;i++){int l=in[i],r=out[i];//l:節(jié)點i的dfs序,r節(jié)點i可以派遣的最靠后的忍者的dfs序 dispatch=query(root[l-1],root[r],1,cnt_money,m);ans=max(ans,(long long)lead[i]*dispatch);}printf("%lld",ans); }

這道題做的時候

1、沒有想到用dfs序鎖定查找區(qū)間

2、ans=max(忍者的領導力*派遣忍者個數(shù)),沒有想到可以枚舉每個忍者,這樣就解決了領導力的問題。對答案的分解能力欠缺

3、答案沒用long long,開始做的時候還想著答案用long long,想先寫出來過了樣例后再改,結果忘了

4、查詢時,如果當前區(qū)間為[x,y],要到節(jié)點的右孩子去查詢,返回的答案應是區(qū)間左右端點左孩子的cnt差,而不是y的cnt。這里與任務查詢系統(tǒng)混了,因為任務查詢系統(tǒng)查詢的區(qū)間是[0,y],0可以省略,所以可以直接用y的cnt、sum

?

轉載于:https://www.cnblogs.com/TheRoadToTheGold/p/6368387.html

總結

以上是生活随笔為你收集整理的[Apio2012]dispatching 主席树做法的全部內容,希望文章能夠幫你解決所遇到的問題。

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