其实非常好理解..就是可以可以合并起来的两个堆嘛><

2809: [Apio2012]dispatching

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             忍者的领导力水平。

  

  嗯这道题XJOI上有然后当时并没有做...看到满屏的splay吓傻

  题意大概就是求出每个节点子树中权值加和不大于一个给定值m的最多个数,也就是尽量取小的

  之前并不会可并堆..然后脑补了一个每次msort的递归做法,T掉了

  实际上我们可以反过来考虑,假设一个节点u的子树的大小为sz,在薪水总数不超过m的情况下能取x个,

  也就是有sz-x个数在这个节点的答案中是用不到的

  实际上在u以上的节点也用不到,有了这个性质我们就可以用可并堆然后每次不停地把子树中最大的删去直到满足sum<=m

/**************************************************************
Problem: 2809
User: mjy0724
Language: C++
Result: Accepted
Time:1284 ms
Memory:9188 kb
****************************************************************/ #include<cstdio>
#include<cstdlib>
#include<cstring>
#define ll long long
#define maxn 100010
struct node{
int l,r;
ll sum,sz;
}a[maxn];
ll n,e,c[maxn],root[maxn],fa[maxn],next[maxn],link[maxn];
ll ans,l[maxn],k;
ll max(ll x,ll y){
if (x>y) return x;return y;
}
void swap(int &x,int &y){
int tmp=x;x=y;y=tmp;
}
int merge(int x,int y){
if (x==||y==) return x+y;
if (c[x]<c[y]) swap(x,y);
a[x].r=merge(a[x].r,y);
swap(a[x].l,a[x].r);
return x; //这条语句经常忘记写啊tat!
}
void add(int x,int y){
fa[++e]=y;next[e]=link[x];link[x]=e;
}
void dfs(int p){
a[p].sum=c[p];a[p].sz=;root[p]=p;
for (int i=link[p];i;i=next[i]){
dfs(fa[i]);
a[p].sum+=a[fa[i]].sum;
a[p].sz+=a[fa[i]].sz;
root[p]=merge(root[p],root[fa[i]]);
}
while (a[p].sum>k){
a[p].sum-=c[root[p]];a[p].sz--;
root[p]=merge(a[root[p]].l,a[root[p]].r);
}
ans=max(ans,(ll)a[p].sz*l[p]);//边dfs边更新答案
}
int main(){
scanf("%lld%lld",&n,&k);
e=;ans=;int x;
for (int i=;i<=n;i++) scanf("%d%lld%lld",&x,&c[i],&l[i]),add(x,i);
dfs();
printf("%lld\n",ans);
}

  

1455: 罗马游戏

Description

罗马皇帝很喜欢玩杀人游戏。 他的军队里面有n个人,每个人都是一个独立的团。最近举行了一次平面几何测试,每个人都得到了一个分数。 皇帝很喜欢平面几何,他对那些得分很低的人嗤之以鼻。他决定玩这样一个游戏。 它可以发两种命令: 1. Merger(i, j)。把i所在的团和j所在的团合并成一个团。如果i, j有一个人是死人,那么就忽略该命令。 2. Kill(i)。把i所在的团里面得分最低的人杀死。如果i这个人已经死了,这条命令就忽略。 皇帝希望他每发布一条kill命令,下面的将军就把被杀的人的分数报上来。(如果这条命令被忽略,那么就报0分)
 
  也是非常裸的一道题...kill操作的时候不仅要把当前root的fa改成新合并之后的根
  新合并之后的根的fa也要及时改掉不然会死循环
  其他的就和上一题差不多了..往往要和并查集结合起来做
  然后这道题加了两行成了左偏树
 /**************************************************************
Problem: 1455
User: mjy0724
Language: C++
Result: Accepted
Time:2320 ms
Memory:21312 kb
****************************************************************/ #include<cstdio>
#include<cstdlib>
#include<cstring>
#define maxn 1000010
struct arr{
int ave,l,r;
}a[maxn];
int fa[maxn],n,m,d[maxn];
bool vis[maxn];
char s[];
int getfa(int x){
if (fa[x]==x) return x;
fa[x]=getfa(fa[x]);
return fa[x];
}
void swap(int &x,int &y){
int tem=x;x=y;y=tem;
}
int merge(int x,int y){
if (x==||y==) return x+y;
if (a[y].ave<a[x].ave) swap(x,y);
a[x].r=merge(a[x].r,y);
if (d[a[x].l]<d[a[x].r]) swap(a[x].l,a[x].r);
d[x]=d[a[x].r]+;
return x;
}
void mer(int x,int y){
if (vis[x]==false||vis[y]==false||getfa(x)==getfa(y)) return;
x=getfa(x);y=getfa(y);
fa[x]=fa[y]=merge(x,y);
}
int sol(int x){
if (vis[x]==false) return ;
int tmp=a[getfa(x)].ave;
vis[fa[x]]=false;
int y=merge(a[fa[x]].l,a[fa[x]].r);
fa[fa[x]]=y;fa[y]=y;
return tmp;
}
int main(){
scanf("%d",&n);
for (int i=;i<=n;i++) scanf("%d",&a[i].ave);
d[]=-;scanf("%d",&m);
memset(vis,true,sizeof(vis));
for (int i=;i<=n;i++) fa[i]=i;
char ch[];int x,y;
for (int i=;i<=m;i++){
scanf("%s",ch);
if (ch[]=='M') scanf("%d%d",&x,&y),mer(x,y);
else scanf("%d",&x),printf("%d\n",sol(x));
}
return ;
}

1367: [Baltic2004]sequence

Description

  这道题的结论证明参见论文

  对于求不下降序列最后的做法就是:维护几段连续的序列,使它们的中位数不下降

  然而转化到递增序列,我们只需要将每个数读进来的之后减去它的下标就可以了

  所以我们对于每一段已求好的序列,既要维护它的中位数,又要支持合并

  因为我们合并的前提是:中位数(i)>中位数(i+1),那么对于合并后的i而言,中位数肯定是不升的

  根据这个性质我们又可以用可并堆了,堆顶元素表示该序列中的中位数

  当堆的元素个数*2>序列长度+1的时候就可以弹出堆顶

  

 /**************************************************************
Problem: 1367
User: mjy0724
Language: C++
Result: Accepted
Time:8440 ms
Memory:35960 kb
****************************************************************/ #include<cstdio>
#include<cstdlib>
#include<cstring>
#define maxn 1000010
#define ll long long
struct arr{
int l,r,sz,rt;
}a[maxn];
int l[maxn],r[maxn],d[maxn],n,cnt;
ll b[maxn];
void swap(int &x,int &y){
int tmp=x;x=y;y=tmp;
}
int merge(int x,int y){
if (x==||y==) return x+y;
if (b[y]>b[x]) swap(x,y);
r[x]=merge(r[x],y);
if (d[l[x]]<d[r[x]]) swap(l[x],r[x]);
d[x]=d[r[x]]+;
return x;//然而啊这道题又是因为这一句没加调了1h
}
void mer(int x,int y){
int lx=a[x].l,rx=a[y].r,size=a[x].sz+a[y].sz,rt=merge(a[x].rt,a[y].rt);
a[x].l=lx;a[x].r=rx;a[x].sz=size;a[x].rt=rt;cnt--;
while (a[x].sz*>(a[x].r-a[x].l+)){
a[x].rt=merge(l[a[x].rt],r[a[x].rt]);a[x].sz--;
}
}
int main(){
scanf("%d",&n);d[]=-;
for (int i=;i<=n;i++) scanf("%d",&b[i]),b[i]-=i;
cnt=;
for (int i=;i<=n;i++){
a[++cnt].l=i;a[cnt].r=i;a[cnt].sz=;a[cnt].rt=i;
while (cnt>&&b[a[cnt].rt]<b[a[cnt-].rt]) mer(cnt-,cnt);
}
ll ans=;
for (int i=;i<=cnt;i++)
for (int j=a[i].l;j<=a[i].r;j++) ans+=abs(b[a[i].rt]-b[j]);
printf("%lld\n",ans);
return ;
}
  

[BZOJ2809&1455&1367]解题报告|可并堆的更多相关文章

  1. [codeforces contest 1119 F] Niyaz and Small Degrees 解题报告 (树形DP+堆)

    interlinkage: http://codeforces.com/contest/1119/problem/F description: 有一颗$n$个节点的树,每条边有一个边权 对于一个$x$ ...

  2. ZOJ 1093 Monkey and Banana (LIS)解题报告

    ZOJ  1093   Monkey and Banana  (LIS)解题报告 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid= ...

  3. 2018.10.26NOIP模拟赛解题报告

    心路历程 预计得分:\(100 + 100 + 70\) 实际得分:\(40 + 100 + 70\) 妈妈我又挂分了qwq..T1过了大样例就没管,直到临考试结束前\(10min\)才发现大样例是假 ...

  4. 2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告

    2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告 勘误1:第6题第4个 if最后一个条件粗心写错了,答案应为1580. 条件应为abs(a[3]-a[7])!=1,宝宝心理苦啊.!感谢zzh ...

  5. 北大ACM试题分类+部分解题报告链接

    转载请注明出处:優YoU http://blog.csdn.net/lyy289065406/article/details/6642573 部分解题报告添加新内容,除了原有的"大致题意&q ...

  6. 冲刺Noip2017模拟赛2 解题报告——五十岚芒果酱

    题1 牛跑步(running) [题目描述] 新牛到部队,CG 要求它们每天早上搞晨跑,从 A 农场跑到 B 农场.从 A 农场到 B 农场中有 n- 个路口,分别标上号,A 农场为 号,B 农场为 ...

  7. Codeforces Round 665 赛后解题报告(暂A-D)

    Codeforces Round 665 赛后解题报告 A. Distance and Axis 我们设 \(B\) 点 坐标为 \(x(x\leq n)\).由题意我们知道 \[\mid(n-x)- ...

  8. Codeforces Round 662 赛后解题报告(A-E2)

    Codeforces Round 662 赛后解题报告 梦幻开局到1400+的悲惨故事 A. Rainbow Dash, Fluttershy and Chess Coloring 这个题很简单,我们 ...

  9. 【九度OJ】题目1107:搬水果 解题报告

    [九度OJ]题目1107:搬水果 解题报告 标签(空格分隔): 九度OJ http://ac.jobdu.com/problem.php?pid=1107 题目描述: 在一个果园里,小明已经将所有的水 ...

随机推荐

  1. oracle和DB2的差异

    1.简介 当今IT的环境正经历着剧烈的变化,依靠单一的关系型数据库管理系统(RDBMS)管理数据的公司开始逐渐减少.分析家的报告指出 ,今天超过90%的公司都拥有不只一种RDBMS.在现在紧张的经济情 ...

  2. mysql导出/导入表结构以及表数据

    导出: 命令行下具体用法如下:  mysqldump -u用戶名 -p密码 -d 数据库名 表名 脚本名; 1.导出数据库为dbname的表结构(其中用戶名为root,密码为dbpasswd,生成的脚 ...

  3. lxs1314 is not in the sudoers file. This incident will be reported.

    虚拟机下面  普通用户用sudo执行命令时报"xxx is not in the sudoers file.This incident will be reported"错误,解决 ...

  4. 第204天:js---重载和多态

    一.根据arguments个数实现重载 js本身不支持重载,所以只能通过其他方式实现,arguments检测传参的个数,然后再执行不同的方式 function add() { var sum = 0 ...

  5. BZOJ4976 宝石镶嵌(动态规划)

    显然被留下的宝石应该贡献至少一位,否则就可以扔掉.所以如果n-k>=logw,直接输出所有数的or.现在n变得和k同阶了.于是设f[i][j]为前i个数or为j时至少选几个数,转移显然.当然可以 ...

  6. 洛谷 P2015 二叉苹果树

    老规矩,先放题面 题目描述 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点) 这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1. 我们用一根树枝两端 ...

  7. HDU.1689 Just a Hook (线段树 区间替换 区间总和)

    HDU.1689 Just a Hook (线段树 区间替换 区间总和) 题意分析 一开始叶子节点均为1,操作为将[L,R]区间全部替换成C,求总区间[1,N]和 线段树维护区间和 . 建树的时候初始 ...

  8. 洛谷 P1924 poj 1038

    Description: 给你一个n * m的方格纸,有一些格子无法被覆盖,然后用2*3的格子覆盖这个方格纸,问你最多能放多少个格子 神级状压 为了弄清楚这道题翻了无数篇解题报告,最后终于搞明白了 用 ...

  9. 同时装了Python3和Python2,怎么用pip?

    问题:同时装了Python3和Python2,怎么用pip? Ubuntu13.04, 系统内同时装了Python3.3 和 2.7 用sudo apt-get install python-pip ...

  10. MATLAB2010安装方法

    MATLAB2010安装方法 第一步选择无网络安装. 选择yes,然后点击next 激活序列号在crack文件夹中的txt文档中 这一步按照图片上的显示操作就可以 选择经典安装 按提示操作,这一步事激 ...