[树剖]月下“毛景树”

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

爬啊爬爬啊爬毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果

“毛景树”上有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之间树枝上毛毛果个数最多有多少个。

输入 第一行一个正整数N。

接下来N-1行,每行三个正整数Ui,Vi和Wi,第i+1行描述第i条树枝。

表示第i条树枝连接节点Ui和节点Vi,树枝上有Wi个毛毛果。 接下来是操作和询问,以“Stop”结束。

输出 对于毛毛虫的每个询问操作,输出一个答案。

样例输入
4
1 2 8
1 3 7
3 4 9
Max 2 4
Cover 2 4 5
Add 1 4 10
Change 1 16
Max 2 4
Stop

样例输出
9
16

提示
【Data Range】
1<=N<=100,000,操作+询问数目不超过100,000。
保证在任意时刻,所有树枝上毛毛果的个数都不会超过10^9个。

吐槽:
做DP做成了个智障,来做下数据结构

分析:
树剖板题,支持单点修改,区间修改,区间覆盖,区间查询即可

代码:(3.5K不多

#include<bits/stdc++.h>
#define ls tr[k].l
#define rs tr[k].r
#define mid (tr[k].l+tr[k].r>>1)
using namespace std;
const int N=100005;
int a[N],tot=0,head[N<<1],nxt[N<<1],vis[N<<1],pt[N],c[N<<1],siz[N],dep[N],fa[N],top[N],hson[N],dfn[N],id[N],cnt=0;
inline void add(int x,int y,int z){vis[++tot]=y,nxt[tot]=head[x];head[x]=tot,c[tot]=z;}
void dfs1(int v){
	int maxn=0;pt[v]=siz[v]=1;
	for(int i=head[v];i;i=nxt[i]){
		int y=vis[i];
		if(pt[y]) continue;
		a[y]=c[i];
		fa[y]=v,dep[y]=dep[v]+1;
		dfs1(y);
		siz[v]+=siz[y];
		if(siz[y]>maxn) {maxn=siz[y],hson[v]=y;}
	}
}
void dfs2(int v){
	dfn[v]=++cnt,id[cnt]=v;
	if(!hson[v]) return;
	top[hson[v]]=top[v];
	dfs2(hson[v]);
	for(int i=head[v];i;i=nxt[i]){
		if(top[vis[i]]) continue;
		top[vis[i]]=vis[i];
		dfs2(vis[i]);
	}
}
struct segtree{int l,r,maxx,add,cov;}tr[N<<2];
inline void pushcov(int k,int v) {tr[k].maxx=v,tr[k].cov=v,tr[k].add=0;}
inline void pushadd(int k,int v) {tr[k].maxx+=v,tr[k].add+=v;}
void pushdown(int k){
	if(~tr[k].cov) pushcov(k<<1,tr[k].cov),pushcov(k<<1|1,tr[k].cov),tr[k].cov=-1;
	if(tr[k].add) pushadd(k<<1,tr[k].add),pushadd(k<<1|1,tr[k].add),tr[k].add=0;
}
void build(int k,int l,int r){
	tr[k].l=l,tr[k].r=r,tr[k].cov=-1;
	if(l==r){tr[k].maxx=a[id[l]];return;}
	build(k<<1,l,mid),build(k<<1|1,mid+1,r);
	tr[k].maxx=max(tr[k<<1].maxx,tr[k<<1|1].maxx);
}
void update1(int k,int ql,int qr,int v){ //add
	if(ql>rs || qr<ls) return;
	if(ql<=ls && qr>=rs) return pushadd(k,v);
	pushdown(k);
	if(qr<=mid) update1(k<<1,ql,qr,v);
	else if(ql>mid) update1(k<<1|1,ql,qr,v);
	else update1(k<<1,ql,mid,v),update1(k<<1|1,mid+1,qr,v);
	tr[k].maxx=max(tr[k<<1].maxx,tr[k<<1|1].maxx);
}
void update2(int k,int ql,int qr,int v){ //cov
	if(ql>rs || qr<ls) return;
	if(ql<=ls && qr>=rs) return pushcov(k,v);
	pushdown(k);
	if(qr<=mid) update2(k<<1,ql,qr,v);
	else if(ql>mid) update2(k<<1|1,ql,qr,v);
	else update2(k<<1,ql,mid,v),update2(k<<1|1,mid+1,qr,v);
	tr[k].maxx=max(tr[k<<1].maxx,tr[k<<1|1].maxx);
}
int query(int k,int ql,int qr){
	if(ql>rs || qr<ls) return 0;
	if(ql<=ls && qr>=rs) return tr[k].maxx;
	pushdown(k);
	if(qr<=mid) return query(k<<1,ql,qr);
	else if(ql>mid) return query(k<<1|1,ql,qr);
	return max(query(k<<1,ql,mid),query(k<<1|1,mid+1,qr));
}
void change1(int x,int y,int v){
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		update1(1,dfn[top[x]],dfn[x],v),x=fa[top[x]];
	}
	if(dep[x]<dep[y]) swap(x,y);
	update1(1,dfn[y]+1,dfn[x],v);
}
void change2(int x,int y,int v){
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		update2(1,dfn[top[x]],dfn[x],v),x=fa[top[x]];
	}
	if(dep[x]<dep[y]) swap(x,y);
	update2(1,dfn[y]+1,dfn[x],v);
}
int ask(int x,int y){
	int ans=0;
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		ans=max(ans,query(1,dfn[top[x]],dfn[x])),x=fa[top[x]];
	}
	if(dep[x]<dep[y]) swap(x,y);
	return max(ans,query(1,dfn[y]+1,dfn[x]));
}
int main(){
	int n;
	cin>>n;
	for(int i=1;i<n;i++){
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);add(y,x,z);
	}
	dfs1(1),top[1]=1;dfs2(1);build(1,1,n);
	char op[10];
	while(true){
		scanf("%s",op);
		if(op[0]=='S') break;
		int x,y;
		scanf("%d%d",&x,&y);
		if(op[0]=='A') {int z;scanf("%d",&z);change1(x,y,z);}
		else if(op[0]=='M') printf("%d\n",ask(x,y));
		else{
			if(op[1]=='o') {int z;scanf("%d",&z);change2(x,y,z);}
			else{
				int u=vis[x*2],v=vis[x*2-1];
				if(dep[u]>dep[v])swap(u,v);
				update2 (1,dfn[v],dfn[v],y);
			}
		}
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值