P4315 月下“毛景树”[树剖]
题目描述
毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园。 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里。
爬啊爬爬啊爬毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果 “毛景树”上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的。但是这棵“毛景树”有着神奇的魔力,他能改变树枝上毛毛果的个数:
- Change k w:将第k条树枝上毛毛果的个数改变为w个。
- Cover u v w:将节点u与节点v之间的树枝上毛毛果的个数都改变为w个。
- Add u v w:将节点u与节点v之间的树枝上毛毛果的个数都增加w个。 由于毛毛虫很贪,于是他会有如下询问:
- Max u v:询问节点u与节点v之间树枝上毛毛果个数最多有多少个。
解析
毒瘤题。
看了讨论才意识到优先级问题,我太菜了。
首先这是个裸的边树剖。一般来说,我们平时做的树剖都是对一系列点权进行操作,而这题要求我们对一系列边权进行操作。
点权转化为边权,是一件很简单的事情。我们只需把每个节点\(x\)与\(father(x)\)之间的边权存在\(x\)的点权上就行了,显然这是不影响正确性的。那么对于一个对\(s\sim t\)的路径操作,我们就只用在原先统计点权的基础上减去\(s,t\)的LCA的点权就可以了。而树剖给了我们一个方便的优化,统计答案时,最后一步一定有\(top[x]=top[y]\)(设\(deep[x]<deep[y]\)),而且它们处于同一条重链上,那么根据树剖的编号规则,\(lca(s,t)\)正是此时的\(x\),我们统计\(calc(id[x]+1,id[y])\)(\(id[x]\)为树剖后\(x\)的编号)即可。
这一题的毒瘤之处在于区间加和区间覆盖之间的优先级。显然,将区间全部修改为同一个值的优先级大于区间加。
我们需要这么搞pushdown:
inline void pushdown(int p)
{
if(t[p].rem!=-1){//区间覆盖为某一值的tag
t[p<<1].max=t[p].rem;
t[p<<1|1].max=t[p].rem;
t[p<<1].rem=t[p].rem;
t[p<<1|1].rem=t[p].rem;
t[p<<1].add=0;t[p<<1|1].add=0;
t[p].rem=-1;
}
if(t[p].add){//区间加的tag
t[p<<1].max+=t[p].add;
t[p<<1|1].max+=t[p].add;
t[p<<1].add+=t[p].add;
t[p<<1|1].add+=t[p].add;
t[p].add=0;
}
}
参考代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<queue>
#include<vector>
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define N 100010
#define MOD 2520
#define E 1e-12
using namespace std;
inline int read()
{
int f=1,x=0;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
struct rec{
int ver,next,edge;
}g[N<<1];
int head[N],tot,n,cnt;
inline void add(int x,int y,int val)
{
g[++tot].ver=y,g[tot].edge=val;
g[tot].next=head[x],head[x]=tot;
}
struct tree{
int l,r;
int max,add,rem;
}t[N<<2];
int top[N],id[N],size[N],son[N],fa[N],dep[N],w[N],wt[N];
struct node{
int u,v;
}a[N];
inline void pushup(int p){t[p].max=max(t[p<<1].max,t[p<<1|1].max);}
inline void pushdown(int p)
{
if(t[p].rem!=-1){
t[p<<1].max=t[p].rem;
t[p<<1|1].max=t[p].rem;
t[p<<1].rem=t[p].rem;
t[p<<1|1].rem=t[p].rem;
t[p<<1].add=0;t[p<<1|1].add=0;
t[p].rem=-1;
}
if(t[p].add){
t[p<<1].max+=t[p].add;
t[p<<1|1].max+=t[p].add;
t[p<<1].add+=t[p].add;
t[p<<1|1].add+=t[p].add;
t[p].add=0;
}
}
inline void build(int p,int l,int r)
{
t[p].l=l,t[p].r=r;t[p].rem=-1;
if(l==r){t[p].max=w[l];return;}
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p);
}
inline void change(int p,int l,int r,int val)
{
if(l<=t[p].l&&t[p].r<=r){
t[p].max+=val;
t[p].add+=val;
return;
}
pushdown(p);
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid) change(p<<1,l,r,val);
if(r>mid) change(p<<1|1,l,r,val);
pushup(p);
}
inline void Cover(int p,int l,int r,int val)
{
if(l<=t[p].l&&t[p].r<=r){
t[p].max=val;
t[p].rem=val;t[p].add=0;
return;
}
pushdown(p);
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid) Cover(p<<1,l,r,val);
if(r>mid) Cover(p<<1|1,l,r,val);
pushup(p);
}
inline int query(int p,int l,int r)
{
if(l<=t[p].l&&t[p].r<=r) return t[p].max;
pushdown(p);
int mid=(t[p].l+t[p].r)>>1;
int val=0;
if(l<=mid) val=max(val,query(p<<1,l,r));
if(r>mid) val=max(val,query(p<<1|1,l,r));
return val;
}
inline void dfs1(int x,int f,int deep)
{
size[x]=1,fa[x]=f,dep[x]=deep;
int maxson=-1;
for(int i=head[x];i;i=g[i].next){
int y=g[i].ver,z=g[i].edge;
if(y==f) continue;
wt[y]=z;
dfs1(y,x,deep+1);
size[x]+=size[y];
if(maxson<size[y]) maxson=size[y],son[x]=y;
}
}
inline void dfs2(int x,int topf)
{
id[x]=++cnt,top[x]=topf,w[cnt]=wt[x];;
if(!son[x]) return;
dfs2(son[x],topf);
for(int i=head[x];i;i=g[i].next){
int y=g[i].ver;
if(y==fa[x]||y==son[x]) continue;
dfs2(y,y);
}
}
inline void ichange(int x,int y,int val)
{
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
change(1,id[top[x]],id[x],val);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
change(1,id[x]+1,id[y],val);
}
inline int iquery(int x,int y)
{
int res=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
res=max(res,query(1,id[top[x]],id[x]));
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
res=max(res,query(1,id[x]+1,id[y]));
return res;
}
inline void cover(int x,int y,int val)
{
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
Cover(1,id[top[x]],id[x],val);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
Cover(1,id[x]+1,id[y],val);
}
int main()
{
n=read();
for(int i=1;i<n;++i){
a[i].u=read(),a[i].v=read();
int z=read();
add(a[i].u,a[i].v,z),add(a[i].v,a[i].u,z);
}
dfs1(1,0,1);
dfs2(1,1);
build(1,1,n);
char op[10];
int x,y,z;
while(~scanf("%s",op)){
if(op[0]=='S') return 0;
if(op[0]=='M'){
x=read(),y=read();
printf("%d\n",iquery(x,y));
}
if(op[0]=='A'){
x=read(),y=read(),z=read();
ichange(x,y,z);
}
if(op[0]=='C'){
if(op[1]=='h'){
x=read(),z=read();
cover(a[x].u,a[x].v,z);
}
else{
x=read(),y=read(),z=read();
cover(x,y,z);
}
}
}
return 0;
}