树链剖分作业小结(中)

前言

补昨天的坑。

今天的模拟赛挂了200pts,是我考的3倍,没有得到大神的保佑。

所幸纳西妲出了,大保底强娶的,留下了开心的眼泪

例题

lg P4315 月下“毛景树”

题目背景

毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园。 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里。

题目描述

爬啊爬爬啊爬毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~~ “毛景树”上有 N N N 个节点和 N − 1 N-1 N1 条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的。但是这棵“毛景树”有着神奇的魔力,他能改变树枝上毛毛果的个数:

  • Change k w:将第k条树枝上毛毛果的个数改变为 w w w 个。
  • Cover u v w:将节点 u u u 与节点 v v v 之间的树枝上毛毛果的个数都改变为 w w w 个。
  • Add u v w:将节点 u u u 与节点 v v v 之间的树枝上毛毛果的个数都增加 w w w 个。

由于毛毛虫很贪,于是他会有如下询问:

  • Max u v:询问节点 u u u 与节点 v v v 之间树枝上毛毛果个数最多有多少个。
做法

看到在树上进行区间修改和查询,很自然就会想到树剖。但我们会发现常规的树链剖分处理的都是点权的问题,而这道题需要我们处理的却是边权,我们需要考虑将边权下放到点上,令当前节点的权值为它与父节点的边的权值,我们就可以用树剖来维护了。

需要特别注意的一点是,两点之间的 l c a lca lca是不能被统计进去的,因为它所代表的权值是 l c a lca lca f a [ l c a ] fa[lca] fa[lca]之间的边权,而这一条边是不在所查询的两点之间的路径上的。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+86;
struct edge{
   
	int y,v,nxt;
}Edge[N<<1];
int Link[N],a[N],len,sze[N],top[N],dep[N],son[N],fa[N],dfn[N],rnk[N],tot,n,fr[N<<1];
void insert(int x,int y,int v) {
   
	Edge[++len]={
   y,v,Link[x]};
	Link[x]=len;fr[len]=x;
}
void dfs1(int now,int fath) {
   
	dep[now]=dep[fath]+1;sze[now]=1;son[now]=-1;fa[now]=fath;
	for(int i=Link[now];i;i=Edge[i].nxt) {
   
		int y=Edge[i].y,v=Edge[i].v;
		if(dep[y]) continue;
		a[y]=v;
		dfs1(y,now);
		sze[now]+=sze[y];
		if(son[now]==-1||sze[son[now]]<sze[y]) son[now]=y;
	}
}
void dfs2(int now,int ttp) {
   
	top[now]=ttp;dfn[now]=++tot;rnk[tot]=a[now];
	if(son[now]==-1) return ;
	dfs2(son[now],ttp);
	for(int i=Link[now];i;i=Edge[i].nxt) {
   
		int y=Edge[i].y;
		if(y==fa[now]||y==son[now]) continue;
		dfs2(y,y);
	}
}
struct tree{
   
	int l,r,mx;
	int lazy_a,lazy_c=-1;
}t[N<<3];
void pushup(int p) {
   
	t[p].mx=max(t[p<<1].mx,t[p<<1|1].mx);
}
void build(int p,int l,int r) {
   
	t[p].l=l;t[p].r=r;t[p].lazy_c=-1;
	if(l==r) {
   
		t[p].mx=rnk[l];
		return ;
	}
	int mid=l+r>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
	pushup(p);
}
void pushdown(int p) {
   
	if(t[p].lazy_c!=-1) {
   
		t[p
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值