USACO Grass Planting
洛谷 P3038 [USACO11DEC]牧草种植Grass Planting
JDOJ 2282: USACO 2011 Dec Gold 3.Grass Planting
Description
Problem 3: Grass Planting [Travis Hance, 2011]
Farmer John has N barren pastures (2 <= N <= 100,000) connected by N-1
bidirectional roads, such that there is exactly one path between any two
pastures. Bessie, a cow who loves her grazing time, often complains about
how there is no grass on the roads between pastures. Farmer John loves
Bessie very much, and today he is finally going to plant grass on the
roads. He will do so using a procedure consisting of M steps (1 <= M <=
100,000).
At each step one of two things will happen:
- FJ will choose two pastures, and plant a patch of grass along each road in
between the two pastures, or,
- Bessie will ask about how many patches of grass on a particular road, and
Farmer John must answer her question.
Farmer John is a very poor counter -- help him answer Bessie's questions!
Input
* Line 1: Two space-separated integers N and M
* Lines 2..N: Two space-separated integers describing the endpoints of
a road.
* Lines N+1..N+M: Line i+1 describes step i. The first character of
the line is either P or Q, which describes whether or not FJ
is planting grass or simply querying. This is followed by two
space-separated integers A_i and B_i (1 <= A_i, B_i <= N)
which describe FJ's action or query.
Output
* Lines 1..???: Each line has the answer to a query, appearing in the
same order as the queries appear in the input.
Sample Input
4 6 1 4 2 4 3 4 P 2 3 P 1 3 Q 3 4 P 1 4 Q 2 4 Q 1 4
Sample Output
2 1 2
Source
题目大意:
给定一个有N个节点的树及M个操作:P操作把一条路径上的边权加一,Q操作询问一条路径上的权值和。
题解:
一道树链剖分的题。(板子题都是紫题了为啥这题还是蓝?)
难点有二:
一:边权转点权。
二:路径和的查询。
对于对树链剖分不是和熟悉的小伙伴,推荐下面的这篇博客,里面有对树链剖分的详细讲解。
我们会发现,树链剖分是一个对点权进行操作的东西。
而题目要求是边权。
所以我们要把边权转点权(废话)。
怎么转呢?
我们会发现一条边连着两个点,因为题目保证给出的是一棵树。我们会发现:一个点可能会有很多个儿子(也就是说有很多连着儿子的边),但是每个儿子只有一个父亲。对应地一层一层类比,我们会发现到叶子节点的时候,它连儿子也没有。
那么我们就可以考虑把边权变成其儿子节点的点权,那么根节点的点权为0,而其他所有边的边权都被映射到了一个点上。
截至这里,我们解决了第一个问题。
如果我们到这里就完事的话,我们最终会全WA。
为什么呢?
还是因为题目中询问的是边权。如果是一个路径的话,比如题目中想求得两条边的权值,但是我们映射完了之后会求得3个点的点权,也就意味着,我们多搞了一个答案。这显然是不符合正确性的。
因为我们是向子节点映射,所以我们多加的其实是目标点的LCA那个点的点权。
所以我们考虑把LCA那个点的点权减掉。
那么我们回顾一下树链剖分求LCA的过程(如有不懂还是翻上面的那篇博客)
我们跳来跳去,最后跳的那一次就能求到LCA,也就是说,我们为了维护查询的正确性,需要把最后一次跳跃的更浅的那个节点变成它的子节点。这样就能保证,LCA不会被加进来。
这个操作的正确性是显然的。因为LCA跳到最后,两个节点必然在一条重链上。而根据树链剖分的预处理操作,一条重链上的节点编号是连续的,那么我们寻找LCA进行跳跃的时候,id[x]就是我们的LCA,那么我们把它+1,就会得到它的儿子节点,这样,LCA就不会被加进来。
代码加深理解:
#include<cstdio>
#include<algorithm>
#include<iostream>
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#define lson pos<<1
#define rson pos<<1|1
using namespace std;
const int maxn=1e5+1;
int n,m,tot,cnt;
int a[maxn];
int head[maxn],nxt[maxn<<1],to[maxn<<1];
int deep[maxn],size[maxn],son[maxn],fa[maxn];
int top[maxn],id[maxn],w[maxn];
int tree[maxn<<2],lazy[maxn<<2];
void add(int x,int y)
{
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void dfs1(int x,int f)
{
deep[x]=deep[f]+1;
size[x]=1;
fa[x]=f;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==f)
continue;
dfs1(y,x);
size[x]+=size[y];
if(!son[x]||size[y]>size[son[x]])
son[x]=y;
}
}
void dfs2(int x,int t)
{
id[x]=++cnt;
w[cnt]=a[x];
top[x]=t;
if(!son[x])
return;
dfs2(son[x],t);
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==fa[x]||y==son[x])
continue;
dfs2(y,y);
}
}
void build(int pos,int l,int r)
{
int mid=(l+r)>>1;
if(l==r)
{
tree[pos]=w[l];
return;
}
build(lson,l,mid);
build(rson,mid+1,r);
tree[pos]=tree[lson]+tree[rson];
}
void mark(int pos,int l,int r,int k)
{
tree[pos]+=(r-l+1)*k;
lazy[pos]+=k;
}
void pushdown(int pos,int l,int r)
{
int mid=(l+r)>>1;
mark(lson,l,mid,lazy[pos]);
mark(rson,mid+1,r,lazy[pos]);
lazy[pos]=0;
}
void update(int pos,int l,int r,int x,int y,int k)
{
int mid=(l+r)>>1;
if(x<=l && r<=y)
{
mark(pos,l,r,k);
return;
}
pushdown(pos,l,r);
if(x<=mid)
update(lson,l,mid,x,y,k);
if(y>mid)
update(rson,mid+1,r,x,y,k);
tree[pos]=tree[lson]+tree[rson];
}
void upd_chain(int x,int y,int k)
{
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])
swap(x,y);
update(1,1,n,id[top[x]],id[x],k);
x=fa[top[x]];
}
if(deep[x]<deep[y])
swap(x,y);
update(1,1,n,id[y]+1,id[x],k);
}
int query(int pos,int l,int r,int x,int y)
{
int ret=0;
int mid=(l+r)>>1;
if(x<=l && r<=y)
return tree[pos];
pushdown(pos,l,r);
if(x<=mid)
ret+=query(lson,l,mid,x,y);
if(y>mid)
ret+=query(rson,mid+1,r,x,y);
return ret;
}
int q_chain(int x,int y)
{
int ret=0;
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])
swap(x,y);
ret+=query(1,1,n,id[top[x]],id[x]);
x=fa[top[x]];
}
if(deep[x]<deep[y])
swap(x,y);
ret+=query(1,1,n,id[y]+1,id[x]);
return ret;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
while(m--)
{
char ch;
cin>>ch;
if(ch=='P')
{
int x,y;
scanf("%d%d",&x,&y);
upd_chain(x,y,1);
}
else
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",q_chain(x,y));
}
}
return 0;
}
USACO Grass Planting的更多相关文章
- spoj - Grass Planting(树链剖分模板题)
Grass Planting 题意 给出一棵树,树有边权.每次给出节点 (u, v) ,有两种操作:1. 把 u 到 v 路径上所有边的权值加 1.2. 查询 u 到 v 的权值之和. 分析 如果这些 ...
- 洛谷P3038 [USACO11DEC]牧草种植Grass Planting
题目描述 Farmer John has N barren pastures (2 <= N <= 100,000) connected by N-1 bidirectional road ...
- [USACO11DEC] Grass Planting (树链剖分)
题目描述 Farmer John has N barren pastures (2 <= N <= 100,000) connected by N-1 bidirectional road ...
- AC日记——[USACO11DEC]牧草种植Grass Planting 洛谷 P3038
题目描述 Farmer John has N barren pastures (2 <= N <= 100,000) connected by N-1 bidirectional road ...
- [Usaco2011 Dec]Grass Planting
Description Farmer John has N barren pastures connected by N-1 bidirectional roads, such that there ...
- 洛谷 P3038 [USACO11DEC]牧草种植Grass Planting
题目描述 Farmer John has N barren pastures (2 <= N <= 100,000) connected by N-1 bidirectional road ...
- P3038 [USACO11DEC]牧草种植Grass Planting
题目描述 Farmer John has N barren pastures (2 <= N <= 100,000) connected by N-1 bidirectional road ...
- [USACO11DEC]Grass Planting
题目大意: 有一棵结点个数为n的树,有m个操作,可以将一段路径上每条边的权值+1或询问某一个边的权值. 思路: 树链剖分+线段树. 轻重链划分本身比较简单,主要需要思考如何用线段树维护每条链. 当x, ...
- 【 SPOJ - GRASSPLA】 Grass Planting (树链剖分+树状数组)
54 种草约翰有 N 个牧场,编号为 1 到 N.它们之间有 N − 1 条道路,每条道路连接两个牧场.通过这些道路,所有牧场都是连通的.刚开始的时候,所有道路都是光秃秃的,没有青草.约翰会在一些道 ...
随机推荐
- 数据仓库006 - MySQL 5.6.x - Linux最佳生产环境离线部署
一.离线安装包 文件准备 这里以mysql-5.6.23-linux-glibc2.5-x86_64.tar.gz为例,记一次MySQL 5.6.x 的生产环境离线部署过程.使用SecureCRT连接 ...
- 探索ASP.Net Core 3.0系列六:ASP.NET Core 3.0新特性启动信息中的结构化日志
前言:在本文中,我将聊聊在ASP.NET Core 3.0中细小的变化——启动时记录消息的方式进行小的更改. 现在,ASP.NET Core不再将消息直接记录到控制台,而是正确使用了logging 基 ...
- 当职责链遇到DI
在GitHub上有个项目,本来是作为自己研究学习.net core的Demo,没想到很多同学在看,还给了很多星,所以觉得应该升成3.0,整理一下,写成博分享给学习.net core的同学们. 项目名称 ...
- resharper 8.2
用户名:ronle注册码:ZoJzmeVBoAv9Sskw76emgksMMFiLn4NM
- cmake打印shell
cmake链接库失败时,可通过打印路径下对应的lib来定位问题 execute_process(COMMAND ls -lt ${CMAKE_CURRENT_SOURCE_DIR}/lib #执行sh ...
- Express 框架以及与http-proxy-middleware整合实现代理
1.Express的简单使用 1.简介 Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具. 使用 Exp ...
- 关于 ReadOnlySpan<T>
using System; using System.Linq; namespace BenchmarkAndSpanExample { public class NameParser { publi ...
- 下载安装office2019
Hello,大家好,我是小喵. 支付宝搜索“321994”,领红包喽! 前几天答应给大家写一篇关于安装激活Office2019的文章.一直在准备,准备制作GIF动图,制作图片等,把我电脑上的Offic ...
- 利用Chrome开发者工具功能进行网页整页截图的方法
第一步:打开chrome开发者工具. 打开你想截图的网页,然后按下 F12(macOS 是 option + command + i)调出开发者工具,接着按「Ctrl + Shift + P」(mac ...
- Spring Cloud Netflix之Eureka Clients服务提供者
之前一章我们介绍了如何搭建Eureka Server,这一章,我们介绍如何搭建服务提供者. Eureka Clients介绍 服务的提供者,通过发送REST请求,将自己注册到注册中心(在高可用注册中心 ...