bzoj2809 [ APIO2012 ] -- 主席树

先求出dfs序,然后枚举管理者。

由于只要求数量最多,所以薪水一定从小到大取,用主席树维护,每次在主席树上二分就可以了。

具体看代码。

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 #define N 100010
 8 #define ll long long
 9 inline char nc(){
10     static char buf[100000],*p1=buf,*p2=buf;
11     if(p1==p2){
12         p2=(p1=buf)+fread(buf,1,100000,stdin);
13         if(p1==p2)return EOF;
14     }
15     return *p1++;
16 }
17 inline void Read(int& x){
18     char c=nc();
19     for(;c<‘0‘||c>‘9‘;c=nc());
20     for(x=0;c>=‘0‘&&c<=‘9‘;x=(x<<3)+(x<<1)+c-48,c=nc());
21 }
22 inline void Read(ll& x){
23     char c=nc();
24     for(;c<‘0‘||c>‘9‘;c=nc());
25     for(x=0;c>=‘0‘&&c<=‘9‘;x=(x<<3)+(x<<1)+c-48,c=nc());
26 }
27 vector<int>g[N];
28 struct Node{
29     int l,r,s;
30     ll S;
31 }c[N*55];
32 struct Ls{
33     ll w;
34     int f;
35 }A[N];
36 ll Ans,m,b[N];
37 int i,j,k,n,Rt[N],r[N],x,y,L[N],l[N],a[N],Cnt,Num,w[N],M;
38 inline ll Max(ll x,ll y){return x<y?y:x;}
39 inline void Dfs(int x){
40     a[++Cnt]=x;l[x]=Cnt;
41     for(int i=0;i<g[x].size();i++)Dfs(g[x][i]);
42     r[x]=Cnt;
43 }
44 inline void Update(int& x,int l,int r,int y,int z,int a){
45     x=++Num;
46     c[x]=c[y];c[x].s++;c[x].S+=a;
47     if(l==r)return;
48     int Mid=l+r>>1;
49     if(z<=Mid)Update(c[x].l,l,Mid,c[y].l,z,a);else Update(c[x].r,Mid+1,r,c[y].r,z,a);
50 }
51 inline int Query(int x,int y,int l,int r,ll s){
52     if(l==r)return c[y].S-c[x].S<=s?c[y].s-c[x].s:0;
53     int Mid=l+r>>1;ll S=s-c[c[y].l].S+c[c[x].l].S;
54     if(S>0)return c[c[y].l].s-c[c[x].l].s+Query(c[x].r,c[y].r,Mid+1,r,S);
55     return Query(c[x].l,c[y].l,l,Mid,s);
56 }
57 inline bool Cmp(Ls a,Ls b){return a.w<b.w;}
58 int main(){
59     Read(n);Read(m);
60     Read(x);Read(b[1]);Read(L[1]);A[1].w=b[1];A[1].f=1;
61     for(i=2;i<=n;i++){
62         Read(x);Read(b[i]);Read(L[i]);
63         g[x].push_back(i);A[i].w=b[i];A[i].f=i;
64     }
65     sort(A+1,A+n+1,Cmp);
66     for(i=1;i<=n;i++)w[A[i].f]=i;
67     Dfs(1);
68     for(i=1;i<=n;i++)Rt[i]=Rt[i-1],Update(Rt[i],1,n,Rt[i],w[a[i]],b[a[i]]);
69     for(i=1;i<=n;i++)Ans=Max(Ans,1ll*L[i]*Query(Rt[l[i]-1],Rt[r[i]],1,n,m));
70     cout<<Ans<<endl;
71     return 0;
72 }

bzoj2809

时间: 2024-12-18 02:05:43

bzoj2809 [ APIO2012 ] -- 主席树的相关文章

BZOJ 2809: [Apio2012]dispatching [主席树 DFS序]

传送门 题意:查询树上根节点值*子树中权值和$\le m$的最大数量 最大值是多少 求$DFS$序,然后变成区间中和$\le m$最多有几个元素,建主席树,然后权值线段树上二分就行了 $WA$:又把边表开小了..... 好吧我$zz$了有根树加无向边干什么.... #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #de

Luogu P1552 [APIO2012]派遣 主席树

题目链接 Click Here 这个题好像大多数人用的都是左偏树啊?这里我来贡献一发主席树的解法. 把题目中的问题抽象出来,其实就是询问每一个点的子树中,工资前\(tot_i\)大的点,使它们的和满足\(\sum cost_i<=m\),在此前提下使\(tot_i\)尽可能大,答案就是\(ans=max(tot_i*lead_i)\). 如果只有一个点的话直接二分一下就好了,但现在树上的每一个点都可能是答案的产生1处.为了便于访问每一棵子树,我们把原先的树按\(dfs\)序划分,子树显然就是连续

主席树复习

T1 [CQOI2015]任务查询系统 n个任务,每个有运行的时间段和优先级,询问某一时刻,优先级最小的个任务的优先级之和 初做:  2017.2.4   http://www.cnblogs.com/TheRoadToTheGold/p/6366165.html 好像是做了一晚上来 现在:2017.3.27   14:17——15:56 用了接近2个小时做了一道以前做过的题,还是弱啊~~~~(>_<)~~~~ difference: 主席树维护的东西不同,以前直接存储优先级之和,现在存储的是

bzoj2809[Apio2012]dispatching

bzoj2809[Apio2012]dispatching 题意: n个点组成一棵树,每个点都有一个领导力和费用,可以让一个点当领导,然后在这个点的子树中选择一些费用之和不超过m的点,得到领导的领导力乘选择的点的个数(领导可不被选择)的利润.求利润最大值.n≤100000 题解: 可并堆.可以得到一个结论,就是在子树中选点的时候,先选所有点,如果费用超了,就不断把费用最大的剔除,知道费用不超,这样得到的选点数量最大,这过程可以用堆维护.同时每个点的堆都可以由子树的堆合并得到,所以需要可并堆. 代

[poj2104]可持久化线段树入门题(主席树)

解题关键:离线求区间第k小,主席树的经典裸题: 对主席树的理解:主席树维护的是一段序列中某个数字出现的次数,所以需要预先离散化,最好使用vector的erase和unique函数,很方便:如果求整段序列的第k小,我们会想到离散化二分和线段树的做法, 而主席树只是保存了序列的前缀和,排序之后,对序列的前缀分别做线段树,具有差分的性质,因此可以求任意区间的第k小,如果主席树维护索引,只需要求出某个数字在主席树中的位置,即为sort之后v中的索引:若要求第k大,建树时反向排序即可 1 #include

【BZOJ 3551】[ONTAK2010] Peaks加强版 Kruskal重构树+树上倍增+主席树

这题真刺激...... I.关于Kruskal重构树,我只能开门了,不过补充一下那玩意还是一棵满二叉树.(看一下内容之前请先进门坐一坐) II.原来只是用树上倍增求Lca,但其实树上倍增是一种方法,Lca只是他的一种应用,他可以搞各种树上问题,树上倍增一般都会用到f数组. |||.我们跑出来dfs序就能在他的上面进行主席树了. IV.别忘了离散. V.他可能不连通,我一开始想到了,但是我觉得出题人可能会是好(S)人(B),但是...... #include <cstdio> #include

[bzoj3932][CQOI2015]任务查询系统-题解[主席树][权值线段树]

Description 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第Ei秒后结束(第Si秒和Ei秒任务也在运行 ),其优先级为Pi.同一时间可能有多个任务同时执行,它们的优先级可能相同,也可能不同.调度系统会经常向 查询系统询问,第Xi秒正在运行的任务中,优先级最小的Ki个任务(即将任务按照优先级从小到大排序后取前Ki个 )的优先级之和是多少.特别的,如

BZOJ_3207_花神的嘲讽计划1_(Hash+主席树)

描述 http://www.lydsy.com/JudgeOnline/problem.php?id=3207 给出一个长度为\(n\)的串,以及\(m\)个长度为\(k\)的串,求每个长度为\(k\)的串在原串\([x,y]\)区间是否出现过. 分析 这道题要求对比长度为\(k\)的串,于是我们把这些串的Hash值都算出来,问题就转化成了求\([x,y]\)的区间中是否出现过某Hash值. 求区间中某一个值出现了多少次,可以用主席树. p.s. 1.学习了主席树指针的写法,比数组慢好多啊...

[主席树]ZOJ3888 Twelves Monkeys

题意:有n年,其中m年可以乘时光机回到过去,q个询问 下面m行,x,y 表示可以在y年穿越回x年, 保证y>x 下面q个询问, 每个询问有个年份k 问的是k年前面 有多少年可以通过一种以上($\ge 2$)方法穿越回去的, 其中时光机只能用一次 比如案例 9 3 3 9 1 6 1 4 1 6 7 2 如图 对于询问 6这一年:1.穿越回第1年  2.等时间过呀过呀过到第9年,再穿越回第1年 那么第1年就有两种方法可以穿越回去, 同理, 2.3.4年也有同样两种方法(回到1再等时间过呀过 过到2