题目描述

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

爬啊爬爬啊爬毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果 “毛景树”上有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;
}

最新文章

  1. 546A. Soldier and Bananas
  2. JVM系列文章(四):类载入机制
  3. span元素定义宽高度
  4. Fishnet(计算几何)
  5. 用C#来开发CAD插件,含源代码
  6. OD: Kernel Exploit - 1
  7. Python算术运算符
  8. union 和 union all 有什么不同?
  9. 读书笔记 C# Type类型与泛型有关的某些属性浅析
  10. centos6下安装opencv3
  11. Could not load file or assembly &#39;System.Data.SQLite&#39; or one of its dependencies. An attempt was made to load a program
  12. linux 信号处理 四
  13. Linux内存子系统及常用调优参数
  14. django 实现全局支持跨域请求
  15. 20155213 《网络攻防》 Exp1 PC平台逆向破解
  16. 一、初识java
  17. 关于K8s集群器日志收集的总结
  18. 20145211黄志远《网络对抗》Exp9 Web安全基础实践
  19. 图像RGB2YUV与YUV2RGB格式互转介绍
  20. 字符串String及字符Char的相关方法

热门文章

  1. docker+k8s基础篇二
  2. Mysql中的读锁,写锁,乐观锁及事务隔离级别和并发问题
  3. Selenium自动化获取WebSocket信息
  4. python学习-66 面向对象3 - 多态
  5. TensorFlow学习笔记(1)—— 基本概念与框架
  6. 用GDB调试程序(四)
  7. windows10环境下的RabbitMQ使用_笔记
  8. nginx反向代理的一次实践
  9. Appium_Page object设计模式
  10. 使用Jenkins自带功能(不用shell)构建Docker镜像并推送到远程仓库