题目描述

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

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

输出格式

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

输入输出样例

输入 #1

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

输出 #1

9

16

说明/提示

1<=N<=100,000,操作+询问数目不超过100,000。

保证在任意时刻,所有树枝上毛毛果的个数都不会超过10^9个。

这个题是道树剖的好题(毒瘤题,debug就要抵好长时间)。

首先,我们要进行边转点的操作。

接着,我们要考虑每一个操作。

这个题要求我们支持区间修改,单点修改,区间加,区间最大值的操作。

对于区间修改和单点修改,我们直接维护一个tag标记。

区间加的操作维护一个add标记。

下放时,tag标记的优先级要高于add标记。在下放完tag标记后,要把add标记清空,便于后面的操作。

剩下的就是线段树和树剖的模板了。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 1e5+10;
string opt;
int n,m,u,v,tot,num,val,x,y;
int size[N],son[N],fa[N],from[N],to[N],head[N],dfn[N],dep[N],a[N],w[N],top[N];
inline int read()
{
int s = 0, w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){s = s * 10+ch -'0'; ch = getchar();}
return s * w;
}
struct node{int to,net,w;}e[N<<1];
void add_(int x,int y,int w)//建边
{
e[++tot].w = w;
e[tot].to = y;
e[tot].net = head[x];
head[x] = tot;
}
void get_tree(int x)//树剖
{
dep[x] = dep[fa[x]] + 1; size[x] = 1;
for(int i = head[x]; i; i = e[i].net)
{
int to = e[i].to;
if(to == fa[x]) continue;
fa[to] = x; a[to] = e[i].w;
get_tree(to);
size[x] += size[to];
if(size[to] > size[son[x]]) son[x] = to;
}
}
void dfs(int x,int topp)
{
top[x] = topp; dfn[x] = ++num; w[dfn[x]] = a[x];
if(son[x]) dfs(son[x],topp);
for(int i = head[x]; i; i = e[i].net)
{
int to = e[i].to;
if(to == fa[x] || to == son[x]) continue;
dfs(to,to);
}
}
struct Tree
{
struct node{
int lc,rc;
int add,maxn,tag;
}tr[N<<2];
#define l(o) tr[o].lc
#define r(o) tr[o].rc
#define add(o) tr[o].add
#define tag(o) tr[o].tag
#define maxn(o) tr[o].maxn
void up(int o)
{
maxn(o) = max(maxn(o<<1),maxn(o<<1|1));
}
void cover(int o,int val){tag(o) = val; maxn(o) = val;}//维护tag标记
void Add(int o,int val){add(o)+= val; maxn(o) += val;}//维护add标记
void down(int o)
{
if(tag(o) != -1)//如果有标记
{
add(o<<1) = add(o<<1|1) = 0;//add标记要清空
cover(o<<1,tag(o)); cover(o<<1|1,tag(o));
tag(o) = -1;
}
if(add(o))
{
Add(o<<1,add(o)); Add(o<<1|1,add(o));
add(o) = 0;
}
}
void build(int o,int L,int R)
{
l(o) = L, r(o) = R; tag(o) = -1;//tag标记初始化为-1,即没有标记
if(L == R)
{
maxn(o) = w[L]; return;
}
int mid = (L+R)>>1;
build(o<<1,L,mid);
build(o<<1|1,mid+1,R);
up(o);
}
void chenge(int o,int L,int R,int val)//区间修改
{
if(L <= l(o) && R >= r(o))
{
cover(o,val);
add(o) = 0; return;//add标记清零
}
down(o);
int mid = (l(o) + r(o))>>1;
if(L <= mid) chenge(o<<1,L,R,val);
if(R > mid) chenge(o<<1|1,L,R,val);
up(o);
}
void change(int o,int L,int R,int val)//区间加
{
if(L <= l(o) && R >= r(o))
{
Add(o,val); return;
}
down(o);
int mid = (l(o) + r(o))>>1;
if(L <= mid) change(o<<1,L,R,val);
if(R > mid) change(o<<1|1,L,R,val);
up(o);
}
int ask(int o,int L,int R)//询问区间最大值
{
int ans = 0;
if(L <= l(o) && R >= r(o)){return maxn(o);}
down(o);
int mid = (l(o) + r(o))>>1;
if(L <= mid) ans = max(ans,ask(o<<1,L,R));
if(R > mid) ans = max(ans,ask(o<<1|1,L,R));
return ans;
}
}tree;
void cover(int x,int y,int val)//跳链修改
{
while(top[x] != top[y])
{
if(dep[top[x]] < dep[top[y]]) swap(x,y);
tree.chenge(1,dfn[top[x]],dfn[x],val);
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x,y);
tree.chenge(1,dfn[x]+1,dfn[y],val);
}
void jia(int x,int y,int val)//跳链加
{
while(top[x] != top[y])
{
if(dep[top[x]] < dep[top[y]]) swap(x,y);
tree.change(1,dfn[top[x]],dfn[x],val);
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x,y);
tree.change(1,dfn[x]+1,dfn[y],val);
}
int query(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,tree.ask(1,dfn[top[x]],dfn[x]));
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x,y);
ans = max(ans,tree.ask(1,dfn[x]+1,dfn[y]));
return ans;
}
int main()
{
n = read();
for(int i = 1; i <= n-1; i++)
{
u = read(); v = read(); val = read();
add_(u,v,val); add_(v,u,val);
from[i] = u; to[i] = v;
}
get_tree(1); dfs(1,1); tree.build(1,1,n); while(1)
{
cin>>opt;
if(opt == "Stop") break;
if(opt == "Change")
{
x = read(); val = read();
int xx = from[x];
int yy = to[x];
if(fa[xx] == yy) tree.chenge(1,dfn[xx],dfn[xx],val);
else tree.chenge(1,dfn[yy],dfn[yy],val); }
if(opt == "Cover")
{
x = read(); y = read(); val = read();
cover(x,y,val);
}
if(opt == "Add")
{
x = read(); y = read(); val = read();
jia(x,y,val);
}
if(opt == "Max")
{
x = read(); y = read();
printf("%d\n",query(x,y));
}
}
return 0;
}

这道题真是毒瘤,对于标记的下放就特别容易搞混。 (debug花了我一个多小时)

ENDING

P 4315 月下毛景树的更多相关文章

  1. BZOJ 1984: 月下“毛景树” [树链剖分 边权]

    1984: 月下“毛景树” Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 1728  Solved: 531[Submit][Status][Discu ...

  2. 【BZOJ1984】月下“毛景树” 树链剖分+线段树

    [BZOJ1984]月下"毛景树" Description 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校 ...

  3. 【BZOJ-1984】月下“毛景树” 树链剖分

    1984: 月下“毛景树” Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 1314  Solved: 416[Submit][Status][Discu ...

  4. Bzoj 1984: 月下“毛景树” 树链剖分

    1984: 月下“毛景树” Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 1282  Solved: 410[Submit][Status][Discu ...

  5. BZOJ1984: 月下“毛景树”

    1984: 月下“毛景树” Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 713  Solved: 245[Submit][Status] Descri ...

  6. P4315 月下“毛景树”

    P4315 月下"毛景树" 题目描述 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里. 爬啊爬~爬啊爬 ...

  7. 树剖+线段树||树链剖分||BZOJ1984||Luogu4315||月下“毛景树”

    题面:月下“毛景树” 题解:是道很裸的树剖,但处理的细节有点多(其实是自己线段树没学好).用一个Dfs把边权下移到点权,用E数组记录哪些边被用到了:前三个更新的操作都可以合并起来,可以发现a到b节点间 ...

  8. [luogu4315]月下“毛景树”

    [luogu4315]月下"毛景树" luogu 联赛前复习一发树剖.不会告诉你WA了4发 #define ls x<<1,l,mid #define rs x< ...

  9. P4315 月下“毛景树”(树链剖分)

    P4315 月下"毛景树"(树链剖分) 题面 简述: 边权转点权(在dfs1处转换) 把一条边权赋值在深度更深的上 需要实现对单边权的染色 , 路径边权的染色 , 路径边权的增加 ...

随机推荐

  1. Shader之溶解效果的几种实现方法

    这里通过 “是否丢弃像素”的2种方法,写2个shader,效果是一样的,也提到了,丢弃某个像素的3种方式. 是否丢弃: 1.通过脚本控制shader变量判断当前是否丢弃像素,需要额外脚本: 2.sha ...

  2. 面试【JAVA基础】阻塞队列

    1.五种阻塞队列介绍 ArrayBlockingQueue 有界队列,底层使用数组实现,并发控制使用ReentrantLock控制,不管是插入操作还是读取操作,都需要获取锁之后才能执行. Linked ...

  3. 深入了解Netty【六】Netty工作原理

    引言 前面学习了NIO与零拷贝.IO多路复用模型.Reactor主从模型. 服务器基于IO模型管理连接,获取输入数据,又基于线程模型,处理请求. 下面来学习Netty的具体应用. 1.Netty线程模 ...

  4. python基础三(集合、文件)

    1.集合定义 集合天生能去重,且与字典一样,无序.集合用大括号括起来,里面的元素之间用逗号分隔,要跟字典区分开. 集合定义方法:s=set() #定义一个空集合 s={'1','a','b','c', ...

  5. boostrap栅格系统自适应的布局

    1.栅格系统 ​ Bootstrap是基于移动优先的原则开发的,使用了一系列的媒体查询(media queries)方法,为我们的布局和界面创建自适应的的分界点.这些分界点主要是基于视口宽度的最小值, ...

  6. 一起来读官方文档-----SpringIOC(04)

    1.4.2.依赖性和详细配置 如上一节所述,您可以将bean属性和构造函数参数定义为对其他托管bean(协作者)的引用或内联定义的值.Spring的基于XML的配置元数据为此目的在其和元素中支持子元素 ...

  7. 数据库漏洞扫描工具scuba

    1.先下载安装scuba 参考地址  https://www.52pojie.cn/thread-702605-1-1.html 百度网盘下载地址: 链接:https://pan.baidu.com/ ...

  8. jmeter中接口测试出现乱码或不识别中文解决办法

    在查看结果是中出现乱码时:jmeter的bin目录下的jmeter.properties下最下面添加sampleresult.default.encoding=UTF-8后重新打开工具就好了 在接口的 ...

  9. ctfhub sql注入 整数型注入

    整数型注入 手工注入 1.查看是否存在sql注入,及sql注入类型 2.确定列数 3.确定注入点,以及数据库版本,数据库名称 4.查表名 5.查字段名以及flag值 获得flag值 sqlmap做法 ...

  10. 学习 | 基于require.js的三级联动菜单【入门】

    主要目的是学习如何使用require.js AMD就是通过延迟和按需加载来解决各个模块的依赖关系,其中require就是AMD的框架之一 它的优点是可以解决以下问题: JS文件的依赖关系. 通过异步加 ...