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;
}
posted @ 2019-10-19 17:02  DarkValkyrie  阅读(125)  评论(0编辑  收藏  举报