【SCOI2018】Tree(LCT)

本文介绍了一种解决树形结构中查询与更新问题的方法,包括两种操作:查询从某个节点出发的最大权值路径和更新特定节点的权值。通过使用自定义数据结构和高效的算法实现,可以在限定的时间和空间内完成大量复杂操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

描述

在大小为 N 的树上,点从 1 到 N 标号,第 i 个点有权值 Ai,现在需要支持两 种操作:

第一种操作格式为“1 U” ,表示询问从 U 出发的简单路径,经过的点权值 之和的最大值;

第二种操作格式为“2 U V” ,表示将 U 的权值修改为 V。

输入

第一行两个整数 N 和 M,表示树的大小和操作数;

第二行 N-1 个整数,第 i 个整数 Pi(1<=Pi<=i)表示第 i+1 个点与 Pi 有边相 连;

第三行 N 个整数,第 i 个整数 Ai 表示第 i 个点的点权;

接下来 M 行,每行为一个询问操作“1 U” 或修改操作“2 U V” ,按操作发 生的先后顺序给出。

输出

对于每个询问操作,输出一个整数,即经过的点权值之和的最大值

样例输入

6 7
1 1 1 3 3
-1 2 -3 4 -5 6
1 2
1 5
1 6
2 4 5
1 2
1 5
1 6

样例输出

5 
-2
6 
6
-2
7

提示

对于 10%的数据,满足:

1<=N<=1000,1<=M<=1000

对于另外 20%的数据,不存在修改操作

对于另外 20%的数据,满足 Pi=i

对于 100%的数据,满足:

1<=N<=100000, 1<=M<=100000

1<=Pi<=i, -10000<=Ai<=10000

1<=U<=n, -10000<=V<=10000

时限4s,空间限制64MB


解析:

实际上按照SCOI的尿性,这道题时间限制没出成1s都已经算是很仁慈了。

但是64MB的空间限制卡点分树直接把一大波人送退役。

于是有神仙提出了什么这道题的DDP做法。

还有什么两个log的链分治。

实际上如果你做完过SPOJ-QTREE系列,这道题的LCT做法相当SB。(虽然也是两个log)

由于我们需要维护子树信息且全局没有Link和cut操作,所以我们放弃makeroot。

每个点开multiset维护向所有虚子树叉出去的最大路径权值和。

实链上维护链顶和链底在当前链上以及当前链上所有点子树中的答案。

显然就可以轻易在access和pushup的时候维护了。

对于询问,直接将询问的点access变成链底,然后回答当前链底的答案就行了。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
#define int ll

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<20|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	inline int getint(){
		re char c;
		re bool f=0;
		while(!isdigit(c=gc()))f|=c=='-';re int num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return f?-num:num;
	}
}
using namespace IO;

using std::cout;
using std::cerr;

cs int N=1e5+1000;
int n,m;

int fa[N],son[N][2];
int sum[N],val[N],lmx[N],rmx[N];
std::multiset<int> s[N];
inline int fir(cs std::multiset<int> &s){return (!s.size())?-0x3f3f3f3f:*--s.end();}

inline void pushup(int u){
	sum[u]=val[u]+sum[son[u][0]]+sum[son[u][1]];
	lmx[u]=std::max(lmx[son[u][0]],sum[son[u][0]]+val[u]+std::max(std::max(0ll,lmx[son[u][1]]),fir(s[u])));
	rmx[u]=std::max(rmx[son[u][1]],sum[son[u][1]]+val[u]+std::max(std::max(0ll,rmx[son[u][0]]),fir(s[u])));
}

inline bool isroot(int u){return son[fa[u]][0]!=u&&son[fa[u]][1]!=u;}
inline bool which(int u){return son[fa[u]][1]==u;}

inline void Rotate(int u){
	int Fa=fa[u],FA=fa[Fa];
	bool pos=which(u);
	if(!isroot(Fa))son[FA][which(Fa)]=u;
	son[Fa][pos]=son[u][!pos];
	if(son[u][!pos])fa[son[Fa][pos]]=Fa;
	son[u][!pos]=Fa;
	fa[Fa]=u,fa[u]=FA;
	pushup(Fa),pushup(u);
}

inline void Splay(int u){
	for(int re Fa=fa[u];!isroot(u);Rotate(u),Fa=fa[u])
	if(!isroot(Fa))Rotate(which(Fa)==which(u)?Fa:u);
}

inline void access(int u){
	for(int re ch=0;u;u=fa[ch=u]){
		Splay(u);
		if(son[u][1])s[u].insert(lmx[son[u][1]]);
		if(ch){
			std::multiset<int>::iterator iter=s[u].find(lmx[ch]);
			if(iter!=s[u].end())s[u].erase(iter);
		}
		son[u][1]=ch;
		pushup(u);
	}
}

signed main(){
	lmx[0]=rmx[0]=-0x3f3f3f3f;
	n=getint(),m=getint();
	for(int re i=2;i<=n;++i)fa[i]=getint();
	for(int re i=1;i<=n;++i)val[i]=getint();
	for(int re i=n;i;--i)pushup(i),s[fa[i]].insert(lmx[i]);
	while(m--)switch(getint()){
		case 1:{
			int u=getint();
			access(u);
			Splay(u);
			cout<<rmx[u]<<"\n";
			break;
		}
		case 2:{
			int u=getint();
			access(u);
			Splay(u);
			val[u]=getint();
			pushup(u);
			break;
		}
	}
	return 0;
}
中描述了一个幼儿园里分配糖果的问题,每个小朋友都有自己的要求。问题的输入包括两个整数NN和KK,表示幼儿园里的小朋友数量和要满足的要求数量。接下来的KK行表示小朋友们的要求,每行有三个数字,XX,AA,BB。如果X=1,表示第AA个小朋友分到的糖果必须和第BB个小朋友分到的糖果一样多;如果X=2,表示第AA个小朋友分到的糖果必须少于第BB个小朋友分到的糖果;如果X=3,表示第AA个小朋友分到的糖果必须不少于第BB个小朋友分到的糖果;如果X=4,表示第AA个小朋友分到的糖果必须多于第BB个小朋友分到的糖果;如果X=5,表示第AA个小朋友分到的糖果必须不多于第BB个小朋友分到的糖果。这个问题可以被看作是一个差分约束系统的问题。 具体地说,可以使用差分约束系统来解决这个问题。差分约束系统是一种通过给变量之间的关系添加约束来求解最优解的方法。对于这个问题,我们需要根据小朋友们的要求建立约束条件,并通过解决这个约束系统来得出最小的糖果数量。 在问题的输入中,X的取值范围为1到5,分别对应不同的关系约束。根据这些约束,我们可以构建一个差分约束图。图中的节点表示小朋友,边表示糖果数量的关系。根据不同的X值,我们可以添加相应的边和权重。然后,我们可以使用SPFA算法(Shortest Path Faster Algorithm)来求解这个差分约束系统,找到满足所有约束的最小糖果数量。 需要注意的是,在读取输入时需要判断X和Y是否合法,即是否满足X≠Y。如果X=Y,则直接输出-1,因为这种情况下无法满足约束条件。 综上所述,为了满足每个小朋友的要求,并且满足所有的约束条件,我们可以使用差分约束系统和SPFA算法来求解这个问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【差分约束系统】【SCOI2011】糖果 candy](https://blog.youkuaiyun.com/jiangzh7/article/details/8872699)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [P3275 [SCOI2011]糖果(差分约束板子)](https://blog.youkuaiyun.com/qq_40619297/article/details/88678605)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值