「JLOI2015」城池攻占

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

分析:

明显城市管辖图是一棵树,设这棵树的最大深度是 deep,暴力做法是对于每个骑士分别统计,则这样复杂度就是 O ( m ∗ d e e p ) O(m*deep) O(mdeep) 1 < = d e e p < = n 1<=deep<=n 1<=deep<=n肯定会T,我们考虑对每个城市维护一个骑士战斗力的小顶堆,不断弹出堆顶元素直到 堆顶战斗力>=防御值, 则堆中剩下的骑士又可以往上继续攻击,统计更新。因为有堆的合并,所以用左偏树,然后节点偏大,所以标记一下(即线段树的lazy数组)

代码:
#include<bits/stdc++.h>
using namespace std;

#define I inline
#define rg register
#define N 300000+10
#define LL long long
#define rep(i,a,b) for(rg int i=a;i<=b;i++)

const int BUF_SIZE = 1 << 22;
char rr[BUF_SIZE], *csy1, *csy2;
#define GC \
    (csy1 == csy2 && (csy2 = (csy1 = rr) + fread(rr, 1, BUF_SIZE, stdin), csy1 == csy2) ? EOF : *csy1++)

I LL rd()
{
	LL x=0,f=0;char c=GC;
	while(!isdigit(c)){f|=c=='-';c=GC;}
	while( isdigit(c)){x=(x<<3)+(x<<1)+(c-48);c=GC;}
	return f?-x:x;
}

LL h[N],a[N],v[N];
LL s[N],lazy_mul[N],lazy_add[N];
int L[N],R[N],dis[N];
int ans1[N],ans2[N],dep[N],rt[N],c[N];
int n,m;

void cal(int u,LL mul,LL add)
{
	if(!u) return;
	s[u]*=mul,s[u]+=add;
	lazy_mul[u]*=mul,lazy_add[u]*=mul,lazy_add[u]+=add;
}

void pushdown(int u)
{
	cal(L[u],lazy_mul[u],lazy_add[u]);
	cal(R[u],lazy_mul[u],lazy_add[u]);
	lazy_mul[u]=1,lazy_add[u]=0;
}

int merge(int x,int y)
{
	if(!x||!y) return x+y;
	pushdown(x);
	pushdown(y);
	if(s[x]>s[y]) swap(x,y);
	R[x]=merge(y,R[x]);
	if(dis[L[x]]<dis[R[x]]) swap(L[x],R[x]);
	dis[x]=dis[R[x]]+1;
	return x;
}

int pop(int u)
{
	return merge(R[u],L[u]);
}

struct node{
	int to,nxt;
}e[N];
int head[N],tot=1;

void addedge(int u,int v)
{
    e[++tot]=(node){v,head[u]};
	head[u]=tot;
}

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]=merge(rt[u],rt[v]);
	}
	while(rt[u]&&s[rt[u]]<h[u])
	{
		pushdown(rt[u]);
		ans1[u]++;
		ans2[rt[u]]=dep[c[rt[u]]]-dep[u];
		rt[u]=pop(rt[u]); 
	}
	if(u==1)
	{
		while(rt[u])
		{
			pushdown(rt[u]);
			ans2[rt[u]]=dep[c[rt[u]]]+1;
		    rt[u]=pop(rt[u]);
		}
		return;
	}
	if(a[u]) cal(rt[u],v[u],0);
	else cal(rt[u],1,v[u]);
}

int main()
{
	n=rd(),m=rd();
	rep(i,1,n) h[i]=rd();
	rep(i,2,n)
	{
		LL f=rd(); a[i]=rd(),v[i]=rd();
		addedge(f,i);
	}
	rep(i,1,m)
	{
		s[i]=rd(),c[i]=rd();
		lazy_mul[i]=1;
		rt[c[i]]=merge(rt[c[i]],i);
	}
	dfs(1);
	rep(i,1,n) printf("%d\n",ans1[i]);
	rep(i,1,m) printf("%d\n",ans2[i]);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值