P 4315 月下毛景树
题目描述
毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园。 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里。
爬啊爬~爬啊爬毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~ “毛景树”上有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 月下毛景树的更多相关文章
- BZOJ 1984: 月下“毛景树” [树链剖分 边权]
		1984: 月下“毛景树” Time Limit: 20 Sec Memory Limit: 64 MBSubmit: 1728 Solved: 531[Submit][Status][Discu ... 
- 【BZOJ1984】月下“毛景树” 树链剖分+线段树
		[BZOJ1984]月下"毛景树" Description 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校 ... 
- 【BZOJ-1984】月下“毛景树”   树链剖分
		1984: 月下“毛景树” Time Limit: 20 Sec Memory Limit: 64 MBSubmit: 1314 Solved: 416[Submit][Status][Discu ... 
- Bzoj 1984: 月下“毛景树”  树链剖分
		1984: 月下“毛景树” Time Limit: 20 Sec Memory Limit: 64 MBSubmit: 1282 Solved: 410[Submit][Status][Discu ... 
- BZOJ1984: 月下“毛景树”
		1984: 月下“毛景树” Time Limit: 20 Sec Memory Limit: 64 MBSubmit: 713 Solved: 245[Submit][Status] Descri ... 
- P4315 月下“毛景树”
		P4315 月下"毛景树" 题目描述 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里. 爬啊爬~爬啊爬 ... 
- 树剖+线段树||树链剖分||BZOJ1984||Luogu4315||月下“毛景树”
		题面:月下“毛景树” 题解:是道很裸的树剖,但处理的细节有点多(其实是自己线段树没学好).用一个Dfs把边权下移到点权,用E数组记录哪些边被用到了:前三个更新的操作都可以合并起来,可以发现a到b节点间 ... 
- [luogu4315]月下“毛景树”
		[luogu4315]月下"毛景树" luogu 联赛前复习一发树剖.不会告诉你WA了4发 #define ls x<<1,l,mid #define rs x< ... 
- P4315 月下“毛景树”(树链剖分)
		P4315 月下"毛景树"(树链剖分) 题面 简述: 边权转点权(在dfs1处转换) 把一条边权赋值在深度更深的上 需要实现对单边权的染色 , 路径边权的染色 , 路径边权的增加 ... 
随机推荐
- Web测试和前端技术
			Html Form表单 用户需要输入内容的地方一般有一个表单元素 method:GET/POST action:要打开/提交的目文件 Table表格 检查表格数据和数据库的一致性 表格的布局检测:填满 ... 
- 精选PDF版本书籍第一期
			福利概述 精选JAVA必读书籍的PDF版本(来源于网络,侵删). Effective java 中文版(第2版) Head First 设计模式(中文版) Java并发编程的艺术 Java技术手册(第 ... 
- Spark应用开发-关联分析
			在机器学习中,常用的主题有分类,回归,聚类和关联分析.而关联分析,在实际中的应用场景,有部分是用于商品零售的分析.在Spark中有相应的案例 在关联分析中,有一些概念要熟悉. 频繁项集,关联规则,支持 ... 
- Mysql批量导入
			这应该是我写Mysql技术的最后一章了吧,短时间内应该不会再写Mysql的文章了,当然疑难杂症除外 insert语句优化 因为之前我也遇到过这样的问题,是我在做数据库适配的时候碰见的,那是我的数据还是 ... 
- 重学Ajax
			什么是Ajax Asynchronous JavaScript and xml 异步的JavaScript和XML 只是一种js的应用,在无需重新加载整个网页的情况下实现部分网页的数据更新的技术.减少 ... 
- 操作DOM对象
			操作DOM对象 目录 操作DOM对象 1. 核心 2. 获得Dom节点 3. 更新节点 1. 操作文本 2. 操作CSS 4. 删除节点 5. 插入节点 1. 追加(将已存在的节点移到后面) 2. 创 ... 
- JDK1.7之前的Bug之静态代码块
			程序的主入口是main方法,但是在jdk1.7之前,可以没有main方法也一样能运行,很是不可思议,到底是什么原因呢?,大家都知道在类中定义了静态代码块的话,是首先执行代码块里的语句的,如果把静态代码 ... 
- 使用Scrcpy实现电脑控制安卓手机
			很多时候我们想要在电脑上使用一些手机软件,使用模拟器当然是一种选择,但是这些模拟器要不然不免费,要不然广告多不放心.Scrcpy是一个开源免费的软件,通过abd命令实现了安卓手机投屏和控制功能,并且支 ... 
- Element-UI:级联选择器:Cannot read property 'level' of null"
			当级联选择时如果其选择内容需要动态变化时,如果没有选择就不会报错的:而当做出选择后又要动态变化级联选择器内容时,就会报错/ 错误:这个错误的原因是当选择后,再更新内容时,选择器仍会关联原来的数据,导致 ... 
- Mysql-Innodb : 从一个字节到整个数据库表了解物理存储结构和逻辑存储结构
			首先要从Innodb怎么看待磁盘物理空间说起 一块原生的(Raw)物理磁盘,可以把他看成一个字节一个字节单元组成的物理存储介质 如果要在这块原生物理空间中插入一条记录,不能单单只插入数据,还需 ... 
