前言
补昨天的坑。
今天的模拟赛挂了200pts,是我考的3倍,没有得到大神的保佑。
所幸纳西妲出了,大保底强娶的,留下了开心的眼泪
例题
题目背景
毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园。 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里。
题目描述
爬啊爬爬啊爬毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~~ “毛景树”上有 N N N 个节点和 N − 1 N-1 N−1 条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的。但是这棵“毛景树”有着神奇的魔力,他能改变树枝上毛毛果的个数:
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