luoguP3261 [JLOI2015]城池攻占

题意

暴力自然是模拟,考虑优化下模拟的过程。

我们对每个点开个左偏树,初始为在该点的骑士,之后dfs过程当中从儿子向父亲合并,同时弹出小于当前点的骑士,增加当前点的答。对于每个骑士的答案,我们记录他的起始点和终点即可。

code:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=300010;
int n,m,cnt;
int head[maxn],def[maxn],type[maxn],delta[maxn],ans1[maxn],ans2[maxn],root[maxn],dep[maxn],st[maxn];
struct edge{int to,nxt;}e[maxn<<1];
struct Heap
{
	#define lc(p) (heap[p].lc)
	#define rc(p) (heap[p].rc)
	#define val(p)(heap[p].val)
	#define dis(p) (heap[p].dis)
	#define tag1(p) (heap[p].tag1)
	#define tag2(p) (heap[p].tag2) 
	int lc,rc;
	int val,dis,tag1,tag2; 
}heap[maxn];
inline int read()
{
	char c=getchar();int res=0,f=1;
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
	return res*f;
}
inline void add(int u,int v)
{
	e[++cnt].nxt=head[u];
	head[u]=cnt;
	e[cnt].to=v;
}
inline void move(int x,int mul,int add)
{
	if(!x)return;
	val(x)*=mul;val(x)+=add;
	tag1(x)*=mul;tag2(x)*=mul;tag2(x)+=add;
}
inline void down(int x)
{
	move(lc(x),tag1(x),tag2(x)),move(rc(x),tag1(x),tag2(x));
	tag1(x)=1,tag2(x)=0;
}
int merge(int x,int y)
{
	if(!x||!y)return x+y;
	down(x),down(y);
	if(val(x)>val(y))swap(x,y);
	rc(x)=merge(rc(x),y);
	if(dis(rc(x))>dis(lc(x)))swap(lc(x),rc(x));
	dis(x)=dis(rc(x))+1;
	return x;
}
void dfs(int x,int pre)
{
	dep[x]=dep[pre]+1;
	for(int i=head[x];i;i=e[i].nxt)if(e[i].to!=pre)dfs(e[i].to,x),root[x]=merge(root[x],root[e[i].to]);
	while(root[x]&&val(root[x])<def[x])
	{
		down(root[x]);
		ans1[x]++;ans2[root[x]]=dep[st[root[x]]]-dep[x];
		root[x]=merge(lc(root[x]),rc(root[x]));
	}
	if(type[x])move(root[x],delta[x],0);
	else move(root[x],1,delta[x]);
}
signed main()
{
	n=read(),m=read();
	for(int i=1;i<=n;i++)def[i]=read();
	for(int i=2;i<=n;i++)
	{
		int x=read();add(i,x),add(x,i);
		type[i]=read(),delta[i]=read();
	}
	dis(0)=-1;
	for(int i=1;i<=m;i++)tag1(i)=1;
	for(int i=1;i<=m;i++)
	{
		int k=read();st[i]=read();
		val(i)=k;
		root[st[i]]=merge(root[st[i]],i);
	}
	dfs(1,0);
	while(root[1])down(root[1]),ans2[root[1]]=dep[st[root[1]]],root[1]=merge(lc(root[1]),rc(root[1]));
	for(int i=1;i<=n;i++)printf("%lld
",ans1[i]);
	for(int i=1;i<=m;i++)printf("%lld
",ans2[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/nofind/p/11984747.html