[JLOI2015]城池攻占--- 左偏树 + lazy-tag

解析

  • P a r t 0 Part_0 Part0:吐槽
    还是欠练啊,上来就是个大根堆直接 T T T飞。
    PS:高三学科狗,暑假来划水
  • p a r t 1 part_1 part1:思路
    将骑士看做堆的元素,树上每个节点看做一个(小根)堆。
    初始化后,从叶子出发,一路向上模拟。
    对于节点 P P P,先将其孩子的堆与之合并,然后去掉牺牲的骑士并计入答案,接着更新活着的其数值(打标记);
    标记: l a z y 1 lazy1 lazy1:乘法 ; l a z y 2 lazy2 lazy2:加法 ; l a z y 3 lazy3 lazy3:骑士攻克城堡数
  • p a r t 2 part_2 part2:注意
    l o n g l o n g long long longlong
    乘加标记的处理顺序
    最后处理掉一号节点中堆的答案标记

代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>

#define IL inline
#define ll long long

using namespace std; 

IL ll read()
{
	ll sum = 0;
	bool f = 0;
	char c = getchar();
	for(; '0' > c || c > '9'; c = getchar())
	if(c == '-') f = 1;
	for(; '0' <= c && c <= '9'; c = getchar())
		sum = sum * 10 + (c - '0');
	return f ? -sum : sum;
}

const int N(300005), M(300005);

//lazy1: mul ; lazy2 : add ; lazy3 : mark2
int ch[M][2], dis[M], lazy3[M];
ll val[M], lazy1[M], lazy2[M];

int point[N]; // 节点i的堆首
bool parm1[N];
ll def[N], parm2[N];
int head[N];
int cnt, nxt[N], to[N];

int mark1[N], mark2[M]; // 牺牲 ; 攻占

IL void Add(int u, int v)
{
	nxt[++cnt] = head[u]; to[cnt] = v; head[u] = cnt;
}

IL void Clean(int u)
{
	int v;
	if(lazy1[u])
	{
		if((v = ch[u][0]))  { lazy1[v] *= lazy1[u]; lazy2[v] *= lazy1[u]; val[v] *= lazy1[u]; }
		if((v = ch[u][1]))  { lazy1[v] *= lazy1[u]; lazy2[v] *= lazy1[u]; val[v] *= lazy1[u]; }
		lazy1[u] = 1;
	}
	if(lazy2[u])
	{
		if((v = ch[u][0])) { lazy2[v] += lazy2[u]; val[v] += lazy2[u]; }
		if((v = ch[u][1])) { lazy2[v] += lazy2[u]; val[v] += lazy2[u]; }
		lazy2[u] = 0;
	}
	if(lazy3[u])
	{
		if((v = ch[u][0])) { lazy3[v] += lazy3[u]; mark2[v] += lazy3[u]; }
		if((v = ch[u][1])) { lazy3[v] += lazy3[u]; mark2[v] += lazy3[u]; }
		lazy3[u] = 0;
	}
}

IL int Merge(int x, int y)
{
	if(!x) return y;
	if(!y) return x;
	Clean(x); Clean(y);
	if(val[x] > val[y]) swap(x, y);
	ch[x][1] = Merge(ch[x][1], y);
	if(dis[ch[x][0]] < dis[ch[x][1]]) swap(ch[x][0], ch[x][1]);
	dis[x] = dis[ch[x][1]] + 1;
	return x;
}

IL void Solve(int u, int p)
{
	for(; u && val[u] < def[p];)
	{
		Clean(u); ++mark1[p];
		u = Merge(ch[u][0], ch[u][1]);
	}
	point[p] = u;
	++lazy3[u]; ++mark2[u];
	if(parm1[p])
	{
		lazy1[u] *= parm2[p]; lazy2[u] *= parm2[p]; val[u] *= parm2[p];
	} else
	{
		lazy2[u] += parm2[p]; val[u] += parm2[p];
	}
}

IL void Dfs(int u)
{
	for(int i = head[u], v; i; i = nxt[i])
	{
		v = to[i];
		Dfs(v);
		if(point[v]) point[u] = Merge(point[u], point[v]);
	}
	if(point[u]) Solve(point[u], u);
}

IL void Get_2(int u)
{
	if(lazy3[u])
	{
		int v;
		if((v = ch[u][0])) { lazy3[v] += lazy3[u]; mark2[v] += lazy3[u]; }
		if((v = ch[u][1])) { lazy3[v] += lazy3[u]; mark2[v] += lazy3[u]; }
		lazy3[u] = 0;
	}
	if(ch[u][0]) Get_2(ch[u][0]);
	if(ch[u][1]) Get_2(ch[u][1]);
}

int main()
{
	int n = read(), m = read();
	for(int i = 1; i <= n; ++i) def[i] = read();
	for(int i = 2; i <= n; ++i)
	{
		Add(read(), i);
		parm1[i] = read(); parm2[i] = read();
	}
	
	for(int i = 1, tmp; i <= m; ++i)
	{
		lazy1[i] = 1;
		val[i] = read();
		tmp = read();
		if(!point[tmp]) point[tmp] = i; else point[tmp] = Merge(point[tmp], i);
	}
	
	Dfs(1);
	
	Get_2(point[1]);
	
	for(int i = 1; i <= n; ++i) printf("%d\n", mark1[i]);
	for(int i = 1; i <= m; ++i) printf("%d\n", mark2[i]);
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值