题目大意:有$n$个点的树,第$i$个节点有一个权值$h_i$,$m$个骑士,第$i$个骑士攻击力为$v_i$,一个骑士可以把从它开始的连续的父亲中比它小的节点攻破,攻破一个节点可以把攻击力加或乘一个数(乘的数大于$0$)(每个骑士独立),问每个骑士可以攻破多少个点,每个点会阻挡住多少个骑士。

题解:可以把所有骑士一起考虑,建一个小根堆,存可以攻打到这个点的骑士,每个若堆顶小于该点,就弹出,写一个打标记的可并堆就行了。

卡点:快读中读入$long\;long$的部分返回值变成$int$

C++ Code:

#include <algorithm>
#include <cstdio>
#include <cctype>
namespace __IO {
namespace R {
int x, ch, f;
inline int read() {
ch = getchar(); f = 1;
while (isspace(ch)) ch = getchar();
if (ch == '-') f = -1, ch = getchar();
for (x = ch & 15, ch = getchar(); isdigit(ch); ch = getchar()) x = x * 10 + (ch & 15);
return x * f;
}
long long X;
inline long long readll() {
ch = getchar(); f = 1;
while (isspace(ch)) ch = getchar();
if (ch == '-') f = -1, ch = getchar();
for (X = ch & 15, ch = getchar(); isdigit(ch); ch = getchar()) X = X * 10 + (ch & 15);
return X * f;
}
}
}
using __IO::R::read;
using __IO::R::readll; #define maxn 300010 int head[maxn], cnt;
struct Edge {
int to, nxt;
} e[maxn << 1];
inline void addedge(int a, int b) {
e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
} namespace Heap {
int fa[maxn], lc[maxn], rc[maxn], dis[maxn];
long long M[maxn], A[maxn], V[maxn];
inline void Mul(int rt, long long num) {
if (rt) M[rt] *= num, A[rt] *= num, V[rt] *= num;
}
inline void Add(int rt, long long num) {
if (rt) A[rt] += num, V[rt] += num;
}
inline void pushdown(int rt) {
long long &__M = M[rt], &__A = A[rt];
if (__M != 1) {
Mul(lc[rt], __M);
Mul(rc[rt], __M);
__M = 1;
}
if (__A) {
Add(lc[rt], __A);
Add(rc[rt], __A);
__A = 0;
}
} int __merge(int x, int y) {
if (!x || !y) return x | y;
pushdown(x), pushdown(y);
if (V[x] > V[y]) std::swap(x, y);
rc[x] = __merge(rc[x], y), fa[rc[x]] = x;
if (dis[lc[x]] < dis[rc[x]]) std::swap(lc[x], rc[x]);
dis[x] = dis[rc[x]] + 1;
return x;
}
int merge(int x, int y) {
fa[x] = fa[y] = 0;
return __merge(x, y);
} int insert(int rt, long long val, int pos) {
V[pos] = val, M[pos] = 1, A[pos] = 0;
return merge(rt, pos);
}
int pop(int rt) {
pushdown(rt);
return merge(lc[rt], rc[rt]);
}
} int n, m;
int a[maxn], c[maxn], dead[maxn], num[maxn];
int rt[maxn], dep[maxn];
long long w[maxn], v[maxn];
void dfs(int u) {
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
dep[v] = dep[u] + 1;
dfs(v);
rt[u] = Heap::merge(rt[u], rt[v]);
}
while (rt[u] && Heap::V[rt[u]] < w[u]) {
num[u]++, dead[rt[u]] = u;
rt[u] = Heap::pop(rt[u]);
}
if (rt[u]) {
if (a[u]) Heap::Mul(rt[u], v[u]);
else Heap::Add(rt[u], v[u]);
}
} int main() {
n = read(), m = read();
for (int i = 1; i <= n; i++) w[i] = readll();
for (int i = 2, fa; i <= n; i++) {
fa = read(), a[i] = read(), v[i] = readll();
addedge(fa, i);
}
for (int i = 1; i <= m; i++) {
long long V = readll(); c[i] = read();
rt[c[i]] = Heap::insert(rt[c[i]], V, i);
}
dfs(dep[1] = 1);
for (int i = 1; i <= n; i++) printf("%d\n", num[i]);
for (int i = 1; i <= m; i++) printf("%d\n", dep[c[i]] - dep[dead[i]]);
return 0;
}

  

[洛谷P3261][JLOI2015]城池攻占的更多相关文章

  1. [洛谷P3261] [JLOI2015]城池攻占(左偏树)

    不得不说,这道题目是真的难,真不愧它的“省选/NOI-”的紫色大火题!!! 花了我晚自习前半节课看题解,写代码,又花了我半节晚自习调代码,真的心态爆炸.基本上改得和题解完全一样了我才过了这道题!真的烦 ...

  2. 洛谷P3261 [JLOI2015]城池攻占(左偏树)

    传送门 每一个城市代表的点开一个小根堆,把每一个骑士合并到它开始攻占的城池所代表的点上 然后开始dfs,每一次把子树里那些还活着的骑士合并上来 然后再考虑当前点的堆,一直pop直到骑士全死光或者剩下的 ...

  3. P3261 [JLOI2015]城池攻占 题解

    题目 小铭铭最近获得了一副新的桌游,游戏中需要用 \(m\) 个骑士攻占 \(n\) 个城池.这 \(n\) 个城池用 \(1\) 到 \(n\) 的整数表示.除 \(1\) 号城池外,城池 \(i\ ...

  4. P3261 [JLOI2015]城池攻占 (左偏树+标记下传)

    左偏树还是满足堆的性质,节点距离就是离最近的外节点(无左或者右儿子  或者二者都没有)的距离,左偏性质就是一个节点左儿子的距离不小于右儿子,由此得:节点距离等于右儿子的距离+1. 本题就是对于每个节点 ...

  5. P3261 [JLOI2015]城池攻占

    思路 左偏树维护每个骑士的战斗力和加入的深度(因为只能向上跳) 注意做乘法的时候加法tag会受到影响 代码 #include <cstdio> #include <algorithm ...

  6. BZOJ 4003 / Luogu P3261 [JLOI2015]城池攻占 (左偏树)

    左偏树裸题,在树上合并儿子传上来的堆,然后小于当前结点防御值的就pop掉,pop的时候统计答案. 修改的话就像平衡树一样打懒标记就行了. 具体见代码 CODE #include<bits/std ...

  7. BZOJ_4003_[JLOI2015]城池攻占_可并堆

    BZOJ_4003_[JLOI2015]城池攻占_可并堆 Description 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池. 这 n 个城池用 1 到 n 的整数表示.除 ...

  8. 【BZOJ4003】[JLOI2015]城池攻占 可并堆

    [BZOJ4003][JLOI2015]城池攻占 Description 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池. 这 n 个城池用 1 到 n 的整数表示.除 1 号 ...

  9. BZOJ4003:[JLOI2015]城池攻占——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4003 https://www.luogu.org/problemnew/show/P3261 小铭 ...

随机推荐

  1. R语言使用过程中出现的问题--读取EXCEL文件

    方法一: 按照R导论中的方法,使用RODBC包, library(RODBC) channel<-odbcConnectExcel("file.xlsx") da2<- ...

  2. hdu1045Fire Net(经典dfs)

    Fire Net Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Su ...

  3. TPO-12 C2 A problem of the TA's payroll

    TPO-12 C2 A problem of the TA's payroll payroll n. 工资单:在册职工人数:工资名单: paycheck n. 付薪水的支票,薪水 paperwork ...

  4. UniMelb Comp30022 IT Project (Capstone) - 2.Vuforia in Unity

    2 Vuforia in Unity Tutorial: https://www.youtube.com/watch?v=X6djed8e4n0&t=213s Preparation: Dow ...

  5. Python全栈 正则表达式(re模块正则接口全方位详解)

    re模块是Python的标准库模块 模块正则接口的整体模式 re.compile 返回regetx对象 finditer fullmatch match search 返回 match对象 match ...

  6. 167. Add Two Numbers【LintCode by java】

    Description You have two numbers represented by a linked list, where each node contains a single dig ...

  7. Click Once使用总结

    做了一个CS结构软件,有十几个用户使用的客户端,因为刚开始试用期间,要不断根据用户使用情况修正问题和添加新功能,所以频繁更新是不可避免的,暂时没有深入去研究软件更新,暂时采取的方式是用户通过FTP自行 ...

  8. LeetCode 700——二叉搜索树中的搜索

    1. 题目 2. 解答 如果根节点为空,直接返回 NULL.如果根节点非空,从根节点开始循环查找,直到节点为空. 如果待查找的值大于当前节点值,节点指向右孩子: 如果待查找的值小于当前节点值,节点指向 ...

  9. LeetCode 145 ——二叉树的后序遍历

    1. 题目 2. 解答 2.1. 递归法 定义一个存放树中数据的向量 data,从根节点开始,如果节点不为空,那么 递归得到其左子树的数据向量 temp,将 temp 合并到 data 中去 递归得到 ...

  10. leetcode个人题解——two sum

    这是leetcode第一题,通过较为简单. 第一题用来测试的,用的c,直接暴力法过, /** * Note: The returned array must be malloced, assume c ...