看着百度文库学习了一个。

  总的来说,左偏树这个可并堆满足 堆的性质 和 左偏 性质。

  bzoj2809: [Apio2012]dispatching

    把每个忍者先放到节点上,然后从下往上合并,假设到了这个点 总值 大于 预算,那么我们把这个 大根堆 的堆顶弹掉就好了,剩下的就是可合并堆。

    感谢prey :)

    

 #include <bits/stdc++.h>
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define drep(i, a, b) for (int i = a; i >= b; i--)
#define REP(i, a, b) for (int i = a; i < b; i++)
#define mp make_pair
#define pb push_back
#define clr(x) memset(x, 0, sizeof(x))
#define xx first
#define yy second
using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fll;
//************************************************ const int maxn = ; struct Ed {
int u, v, nx; Ed() {}
Ed(int _u, int _v, int _nx) :
u(_u), v(_v), nx(_nx) {}
} E[maxn];
int G[maxn], edtot;
void addedge(int u, int v) {
E[++edtot] = Ed(u, v, G[u]);
G[u] = edtot;
} int pre[maxn], C[maxn], L[maxn], son[maxn];
struct node {
int key, dis, l, r, sz;
} heap[maxn];
int ndtot; int root[maxn];
ll M;
template <typename T> inline void MaxT (T &a, const T b) { if (a < b) a = b; }
ll ans = -;
int merge(int x, int y) {
if (!x) return y;
if (!y) return x;
if (heap[x].key < heap[y].key) swap(x, y);
heap[x].r = merge(heap[x].r, y);
heap[x].sz = heap[heap[x].l].sz + heap[heap[x].r].sz + ;
if (heap[heap[x].l].dis < heap[heap[x].r].dis) swap(heap[x].l, heap[x].r);
heap[x].dis = heap[heap[x].r].dis + ;
return x;
}
ll solve(int x) {
ll sum = C[x];
heap[root[x] = ++ndtot] = (node) {C[x], , , , };
for (int i = G[x], y; i; i = E[i].nx) {
sum += solve(y = E[i].v);
root[x] = merge(root[x], root[y]);
}
while (sum > M) sum -= heap[root[x]].key, root[x] = merge(heap[root[x]].l, heap[root[x]].r);
MaxT(ans, 1ll * heap[root[x]].sz * L[x]);
return sum;
} int main() {
int n; scanf("%d%lld", &n, &M);
int rt;
rep(i, , n) {
scanf("%d%d%d", pre + i, C + i, L + i);
son[pre[i]]++;
if (pre[i] == ) rt = i;
addedge(pre[i], i);
}
solve(rt);
printf("%lld\n", ans);
return ;
}

  bzoj4003: [JLOI2015]城池攻占

    堆上打个lazytag即可,可以表示成 tag_a * x + tag_b 的形式,标记的合并也很简单,tag_a2 * (tag_a1 * x + tag_b1) + tag_b2,乘开就好。

 #include <bits/stdc++.h>
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define drep(i, a, b) for (int i = a; i >= b; i--)
#define REP(i, a, b) for (int i = a; i < b; i++)
#define mp make_pair
#define pb push_back
#define clr(x) memset(x, 0, sizeof(x))
#define xx first
#define yy second
using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fll;
//************************************************ const int maxn = ; struct Ed {
int u, v, nx; Ed() {}
Ed(int _u, int _v, int _nx) :
u(_u), v(_v), nx(_nx) {}
} E[maxn];
int G[maxn], edtot;
void addedge(int u, int v) {
E[++edtot] = Ed(u, v, G[u]);
G[u] = edtot;
} struct node {
int dis, l, r, sz;
ll key, tag_a, tag_b;
int id;
} heap[maxn];
int ndtot; ll hp[maxn], A[maxn], V[maxn];
int pre[maxn], root[maxn];
ll S[maxn], C[maxn]; void Push_down(int x) {
if (heap[x].tag_a == && heap[x].tag_b == ) return;
int l = heap[x].l, r = heap[x].r;
heap[l].tag_a *= heap[x].tag_a, heap[l].tag_b = heap[l].tag_b * heap[x].tag_a + heap[x].tag_b;
heap[r].tag_a *= heap[x].tag_a, heap[r].tag_b = heap[r].tag_b * heap[x].tag_a + heap[x].tag_b;
heap[l].key = heap[l].key * heap[x].tag_a + heap[x].tag_b;
heap[r].key = heap[r].key * heap[x].tag_a + heap[x].tag_b;
heap[x].tag_a = , heap[x].tag_b = ;
return;
} int merge(int x, int y) {
if (!x) return y;
if (!y) return x;
Push_down(x), Push_down(y);
if (heap[x].key > heap[y].key) swap(x, y);
heap[x].r = merge(heap[x].r, y);
heap[x].sz = heap[heap[x].l].sz + heap[heap[x].r].sz + ;
if (heap[heap[x].l].dis < heap[heap[x].r].dis) swap(heap[x].l, heap[x].r);
heap[x].dis = heap[heap[x].r].dis + ;
return x;
} int Stop[maxn], Peo[maxn];
int dep[maxn];
void solve(int x) {
for (int i = G[x], y; i; i = E[i].nx) {
dep[y = E[i].v] = dep[x] + ;
solve(y);
root[x] = merge(root[x], root[y]);
}
Push_down(root[x]);
while (root[x] && heap[root[x]].key < hp[x]) {
Push_down(root[x]);
Stop[heap[root[x]].id] = x;
Peo[x]++;
root[x] = merge(heap[root[x]].l, heap[root[x]].r);
}
if (root[x]) {
Push_down(root[x]);
if (A[x] == ) heap[root[x]].tag_b = V[x], heap[root[x]].key += V[x];
else heap[root[x]].tag_a = V[x], heap[root[x]].key *= V[x];
}
} int main() {
int n, m; scanf("%d%d", &n, &m);
rep(i, , n) scanf("%lld", hp + i);
rep(i, , n) {
scanf("%d%lld%lld", pre + i, A + i, V + i);
addedge(pre[i], i);
}
rep(i, , m) {
scanf("%lld%lld", S + i, C + i);
heap[++ndtot] = (node) {, , , , S[i], , , i};
root[C[i]] = merge(root[C[i]], ndtot);
}
solve();
rep(i, , n) printf("%d\n", Peo[i]);
rep(i, , m) printf("%d\n", Stop[i] ? dep[C[i]] - dep[Stop[i]] : dep[C[i]] + );
}

左偏树初步 bzoj2809 & bzoj4003的更多相关文章

  1. 【bzoj2809】[Apio2012]dispatching 左偏树

    2016-05-31  15:56:57 题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2809 直观的思想是当领导力确定时,尽量选择薪水少的- ...

  2. 【BZOJ4003】【JLOI2015】城池攻占(左偏树)

    题面 题目描述 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池.这 n 个城池用 1 到 n 的整数表示.除 1 号城池外,城池 i 会受到另一座城池 fi 的管辖,其中 fi ...

  3. 【BZOJ2809】【APIO2012】Dispatching(左偏树)

    题面 Description 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.在这个帮派里,有一名忍者被称之为 Master.除了 Master以外,每名忍者都有且仅有一个 ...

  4. 左偏树(BZOJ4003)

    左偏树打个标记,没了. #include <cstdio> #include <vector> using namespace std; typedef long long l ...

  5. bzoj2809 [Apio2012]dispatching(左偏树)

    [Apio2012]dispatching Description 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.在这个帮派里,有一名忍者被称之为 Master.除了 M ...

  6. [BZOJ2809][Apio2012]dispatching(左偏树)

    首先对于一个节点以及它的子树,它的最优方案显然是子树下选最小的几个 用左偏树维护出每棵子树最优方案的节点,记录答案 然后它的这棵树可以向上转移给父节点,将所有子节点的左偏树合并再维护就是父节点的最优方 ...

  7. 【BZOJ2809】[APIO2012] dispatching(左偏树例题)

    点此看题面 大致题意: 有\(N\)名忍者,每名忍者有三个属性:上司\(B_i\),薪水\(C_i\)和领导力\(L_i\).你要选择一个忍者作为管理者,然后在所有被他管理的忍者中选择若干名忍者,使薪 ...

  8. 【bzoj2809】[Apio2012]dispatching (左偏树)

    我们需要枚举根,然后从其子树内选尽量多的点,薪水不超过M,可是暴力复杂度不对.于是考虑自下而上合并树(开始每棵树内只有一个节点,就是自己) 每个树是一个堆,我们维护树的节点个数和薪水总和,合并时,不断 ...

  9. bzoj2809 [Apio2012]dispatching——左偏树(可并堆)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2809 思路有点暴力和贪心,就是 dfs 枚举每个点作为管理者: 当然它的子树中派遣出去的忍者 ...

随机推荐

  1. Android中ViewPager如何设置不能通过屏幕左右滑动来切换页面

    //很多时候,我想禁止用户通过屏幕的左右滑动来切换界面!如何实现! //创建一个类继承viewpager,实现 onTouchEvent   和   onInterceptTouchEvent方法,都 ...

  2. windows程序设计(二)

    MFC架构组成 1.CWinApp的派生类 2.必须在全局区定义一个派生类的对象 3.在CWinApp派生类内必须要有InitInstance虚函数的重写函数 在MFC软件工程以App类中的InitI ...

  3. FlashDevelop调试Air出错

    按下F5调试命令行窗口出现错误: Starting AIR Debug Launcher... invalid application descriptor: Unknown namespace: h ...

  4. 转:WebDriver(Selenium2) 处理可能存在的JS弹出框

    在自动化测试过程中,有些情况下我们会遇到一些潜在的Javascript弹出框.(即某些条件下才会出现,不是固定出现),然后如果当这种弹出框出现,我们没有加以处理,WebDriver将无法进行下一步的操 ...

  5. android--listview设置高度

    android:layout_height="25dp"这么设置根本就没有用. 我们必须要设置android:minHeight="25dp"这样才行.

  6. Disassembly3:variable

    Initializer C++ Primer上说:如果未初始化的Built-in type是定义在function外部的,那么它将自动被初始化为“0”:如果uninitialized的built-in ...

  7. 删除正在登录的SQL账号

    exec sp_who '用户名' kill @spid sp_droplogin 用户名

  8. 看详细的tomcat报错信息

    WEB-INF/classes目录下新建一个文件叫logging.properties handlers = org.apache.juli.FileHandler, java.util.loggin ...

  9. JSP标准标签库(JSTL)--核心标签库 c

    核心标签库是JSTL中最重要的部分,可以完成输出,判断,迭代等操作 功能分类: 1. 基本标签: <c:out>:输出属性内容 <c:set>:设置属性内容 <c:rem ...

  10. C#获取客服端ip和用户名

    . 在asp.Net中专用属性: 获取服务器电脑名:page.server.manchinename 获取用户信息:page.user 获取客户端电脑名:page.request.userhostna ...