BZOJ2809-左偏樹合并

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

1 ≤N ≤ 100,000 忍者的個數;
1 ≤M ≤ 1,000,000,000 薪水總預算;
0 ≤Bi < i 忍者的上級的編號;
1 ≤Ci ≤ M 忍者的薪水;
1 ≤Li ≤ 1,000,000,000 忍者的領導力水平。

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

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,沒有超過總預算 4。因為派遣了 2 個忍者并且管理者的領導力為3,用戶的滿意度為 2,是可以得到的用戶滿意度的最大值。

我們需要處理出每個節點的孩子中滿足條件的盡可能多的節點,但是我們如果從上往下遍歷處理的話顯然會超時O(n^2)。

所以我們需要從下往上進行處理,盡可能地利用以前的信息,所以不妨對每個節點使用一個優先隊列,將滿足條件的都放進去,如果工資已經高于能負擔的工資,就把工資最高的那個人去掉。然后將相鄰兩個節點進行合并。為了提高效率,我們應當先處理重孩子,再處理輕孩子。

可是這樣使用STL自帶的優先隊列復雜度還不夠優秀,我們可以針對這個問題實現我們自己的優先隊列,所用的數據結構就是左偏樹

左偏樹是一種二叉堆,這種堆可以合并出高度比較低的樹,具體就是通過節點x到沒有右子樹的節點y的距離來進行判斷,及時交換左右孩子,從而使得堆不會變得很長。

這樣的堆有利于再和其他的堆進行合并。

合并的時候:從上往下合并,不斷地把根節點更大的右兒子和另一個堆合并。(可以證明這樣的復雜度最優秀)

具體到這個問題中,我們用節點類型存儲每個節點的數據,可是每個節點的根節點卻不一定是他本身,在二叉堆構造過程中,原本的位置已經改變,為了記錄這種改變,我們用root數組記錄在左偏樹中該節點的父親節點。(在訪問到他為止左偏樹中的節點都是實際樹形關系中他的孩子和他本身)

當目前工資已經超過最大工資的時候,我們就刪去堆頂元素(貪心思想,堆頂的工資最高,刪去他最劃算)

借鑒了網上的代碼加上自己的思考,發現自己這樣寫雖然沒有什么錯誤,但是還是應該把用于記錄堆關系的和用于記錄樹關系的數據分開,混在一起導致容易理解錯誤。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<climits>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<queue>
#include<set>
#include<map>
#include<cmath>
#define rep(i,x,n) for(register int i=x;i<=n;i++) using namespace std;typedef long long ll;
const int MAXN=1e5+5;
struct Node
{int cost; ll ctrl;int rson,lson,dis;
}Tree[MAXN];
int nex[MAXN];
int head[MAXN],num=0;
int N; ll M;
int root[MAXN],sz[MAXN]; ll sum[MAXN];
ll ans=0;int Merge(int x,int y)
{if(!x || !y) return x+y;if(Tree[x].cost<Tree[y].cost) swap(x,y);Tree[x].rson=Merge(Tree[x].rson,y);if(Tree[Tree[x].rson].dis> Tree[Tree[x].lson].dis) swap(Tree[x].rson,Tree[x].lson);Tree[x].dis=Tree[Tree[x].rson].dis+1;return x;
}void Delete(int& x)
{x=Merge(Tree[x].lson,Tree[x].rson);
}int dfs(int x)
{root[x]=x;sum[x]=Tree[x].cost; sz[x]=1;for(int i=head[x];i;i=nex[i]){dfs(i);root[x]=Merge(root[x],root[i]);sum[x]+=sum[i]; sz[x]+=sz[i];}while(sum[x]>M){sum[x]-=Tree[root[x]].cost;sz[x]--;Delete(root[x]);}ans=max(ans,sz[x]*Tree[x].ctrl);
}int main()
{scanf("%d%lld",&N,&M);int t; //int Master=-1;rep(i,1,N){scanf("%d",&t);//if(t==0) Master=i;nex[i]=head[t]; head[t]=i;scanf("%d%lld",&Tree[i].cost,&Tree[i].ctrl);}dfs(1);printf("%lld",ans);return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/383768.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/383768.shtml
英文地址,請注明出處:http://en.pswp.cn/news/383768.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

處理大并發之一 對epoll的理解,epoll客戶端服務端代碼

http://blog.csdn.net/zhuxiaoping54532/article/details/56494313處理大并發之一對epoll的理解&#xff0c;epoll客戶端服務端代碼序言&#xff1a;該博客是一系列的博客&#xff0c;首先從最基礎的epoll說起&#xff0c;然后研究libevent源碼及使用方法&#xff0c;最后研究n…

epoll詳解

http://blog.csdn.net/majianfei1023/article/details/45772269歡迎轉載&#xff0c;轉載請注明原文地址&#xff1a;http://blog.csdn.net/majianfei1023/article/details/45772269一.基本概念&#xff1a;1.epoll是什么&#xff1a;epoll是Linux內核為處理大批量文件描述符而…

數據分割-并查集+set

小w來到百度之星的賽場上&#xff0c;準備開始實現一個程序自動分析系統。 這個程序接受一些形如xixj 或 xi≠xj 的相等/不等約束條件作為輸入&#xff0c;判定是否可以通過給每個 w 賦適當的值&#xff0c;來滿足這些條件。 輸入包含多組數據。 然而粗心的小w不幸地把每組數據…

linux c++線程池的實現

http://blog.csdn.net/zhoubl668/article/details/8927090?t1473221020107 線程池的原理大家都知道&#xff0c;直接上代碼了^_^ Thread.h [cpp] view plaincopy #ifndef __THREAD_H #define __THREAD_H #include <vector> #include <string> #inc…

樹啟發式合并入門

所謂啟發式合并&#xff0c;就是一種符合直覺的合并方法&#xff1a;將小的子樹合并在大的子樹上。 這些問題一般是相似的問題背景&#xff1a;都是樹上的計數問題&#xff0c;都不能直接從上往下進行暴力&#xff0c;都需要從下往上計數時對子樹信息進行運算從而得到父親節點的…

鏈棧基本操作

http://blog.csdn.net/jwentao01/article/details/46765517###;棧基本概念&#xff1a; 棧&#xff08;stack&#xff09;是限定在表尾進行插入和刪除操作的線性表&#xff08;或單鏈表&#xff09;。 //只能在一段進行插入和刪除&#xff0c;因此不存在&#xff0c;在中間進行…

Linux網絡編程---I/O復用模型之select

https://blog.csdn.net/men_wen/article/details/53456435Linux網絡編程—I/O復用模型之select 1. IO復用模型 IO復用能夠預先告知內核&#xff0c;一旦發現進程指定的一個或者多個IO條件就緒&#xff0c;它就通知進程。IO復用阻塞在select或poll系統調用上&#xff0c;而不是阻…

UVa12633-Super Rooks on Chessboard-容斥+FFT

題目大意就是給你一個R*C的棋盤&#xff0c;上面有超級兵&#xff0c;這種超級兵會攻擊 同一行、同一列、同一主對角線的所有元素&#xff0c;現在給你N個超級兵的坐標&#xff0c;需要你求出有多少方塊是不能被攻擊到的(R,C,N<50000) 遇到這種計數問題就要聯想到容斥&#…

Linux網絡編程---I/O復用模型之poll

https://blog.csdn.net/men_wen/article/details/53456474Linux網絡編程—I/O復用模型之poll 1.函數poll poll系統調用和select類似&#xff0c;也是在指定時間內輪詢一定數量的文件描述符&#xff0c;以測試其中是否有就緒者。 #include <poll.h>int poll(struct pollfd…

FFT模板

整理了一下&#xff0c;自己寫了一下模板 const double PIacos(-1.0); struct complex {double r,i;complex(double _r0,double _i0):r(_r),i(_i){}complex operator (const complex &b) {return complex(rb.r,ib.i);}complex operator -(const complex &b) {return c…

Linux網絡編程---I/O復用模型之epoll

https://blog.csdn.net/men_wen/article/details/53456474 Linux網絡編程—I/O復用模型之epoll 1. epoll模型簡介 epoll是Linux多路服用IO接口select/poll的加強版&#xff0c;e對應的英文單詞就是enhancement&#xff0c;中文翻譯為增強&#xff0c;加強&#xff0c;提高&…

POJ 1741tree-點分治入門

學習了一下點分治&#xff0c;如果理解有誤還請不吝賜教。 為了快速求得樹上任意兩點之間距離滿足某種關系的點對數&#xff0c;我們需要用到這種算法。 點分治是樹上的一種分治算法&#xff0c;依靠樹和子樹之間的關系進行分治從而降低復雜度。 和其他樹上的算法有一些區別…

基于單鏈表的生產者消費者問題

『生產者與消費者問題分析』「原理」生產者生產產品&#xff0c;消費者消費產品。產品如果被消費者消費完了&#xff0c;同時生產者又沒有生產出產品&#xff0c;消費者 就必須等待。同樣的&#xff0c;如果生產者生產了產品&#xff0c;而消費者沒有去消費&#x…

C++智能指針(一)智能指針的簡單介紹

https://blog.csdn.net/nou_camp/article/details/70176949C智能指針 在正式了解智能指針前先看一下下面的一段代碼 #include<iostream> using namespace std; class A { public:A():_ptr(NULL), _a(0){}~A(){} public:int* _ptr;int _a; };void test() {A a;int *p1 ne…

聰聰可可-點分治

聰聰和可可是兄弟倆&#xff0c;他們倆經常為了一些瑣事打起來&#xff0c;例如家中只剩下最后一根冰棍而兩人都想吃、兩個人都想玩兒電腦&#xff08;可是他們家只有一臺電腦&#xff09;……遇到這種問題&#xff0c;一般情況下石頭剪刀布就好了&#xff0c;可是他們已經玩兒…

C++智能指針(二)模擬實現三種智能指針

https://blog.csdn.net/nou_camp/article/details/70186721在上一篇博客中提到了Auto_ptr(C智能指針&#xff08;一&#xff09;)&#xff0c;下面進行模擬實現Auto_ptr 采用類模板實現 #include<iostream> using namespace std; template<class T> class Autoptr …

Prime Distance On Tree-樹分治+FFT

題目描述 Problem description. You are given a tree. If we select 2 distinct nodes uniformly at random, what’s the probability that the distance between these 2 nodes is a prime number? Input The first line contains a number N: the number of nodes in this…

C++智能指針(三)總結

https://blog.csdn.net/nou_camp/article/details/70195795 在上一篇博客中&#xff08;C智能指針&#xff08;二&#xff09;&#xff09;模擬實現了三種智能指針。 其中最好的就是shared_ptr,但是這并不代表它就是最完美的&#xff0c;它也有問題&#xff0c;這個問題就是循環…

POJ2114-Boatherds-樹分治

題目描述 Boatherds Inc. is a sailing company operating in the country of Trabantustan and offering boat trips on Trabantian rivers. All the rivers originate somewhere in the mountains and on their way down to the lowlands they gradually join and finally th…

c++11 你需要知道這些就夠了

https://blog.csdn.net/tangliguantou/article/details/50549751c11新特性舉著火把尋找電燈今天我就權當拋磚引玉&#xff0c;如有不解大家一起探討。有部分內容是引用自互聯網上的內容&#xff0c;如有問題請聯系我。T&& 右值引用 std::move 右值引用出現之前我們只能…