洛谷P3038 [USACO11DEC]牧草种植Grass Planting
题目描述
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!
给出一棵n个节点的树,有m个操作,操作为将一条路径上的边权加一或询问某条边的权值。
输入输出格式
输入格式:
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.
输出格式:
- Lines 1..???: Each line has the answer to a query, appearing in the same order as the queries appear in the 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
2
1
2
树链剖分的裸题
但是这个题是在边上进行操作
我们考虑把边上的操作转移到点上
首先想一下最简单的链的情况
对于区间$[l,r]$的操作会影响$r-l+1$个点,但只会影响$r-l$条边
那么我们可以把每条边的边权都放在与它相连的两个点中深度较深的点上
所以我们每次修改的时候都对$(l,r]$进行修改
查询的时候也如此,
具体怎么实现呢?so easy:joy:
只需要在查询/修改的时候把左区间+1即可
注意特判一下x==y的情况
#include<iostream>
#include<cstdio>
#include<cstring>
#define ls k<<1
#define rs k<<1|1
#define LL long long int
using namespace std;
const int MAXN=1e6+;
inline int read()
{
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'',c=getchar();}
return x*f;
}
int root=;
struct node
{
int u,v,w,nxt;
}edge[MAXN];
int head[MAXN];
int num=;
inline void AddEdge(int x,int y)
{
edge[num].u=x;
edge[num].v=y;
edge[num].nxt=head[x];
head[x]=num++;
}
struct Tree
{
int l,r,f,w,siz;
}T[MAXN];
int a[MAXN],b[MAXN],tot[MAXN],idx[MAXN],deep[MAXN],son[MAXN],top[MAXN],fa[MAXN],cnt=;
void update(int k)
{
T[k].w=T[ls].w+T[rs].w;
}
void PushDown(int k)
{
if(!T[k].f) return ;
T[ls].w+=T[k].f*T[ls].siz;
T[rs].w+=T[k].f*T[rs].siz;
T[ls].f+=T[k].f;
T[rs].f+=T[k].f;
T[k].f=;
}
int dfs1(int now,int f,int dep)
{
deep[now]=dep;
tot[now]=;
fa[now]=f;
int maxson=-;
for(int i=head[now];i!=-;i=edge[i].nxt)
{
if(edge[i].v==f) continue;
tot[now]+=dfs1(edge[i].v,now,dep+);
if(tot[edge[i].v]>maxson) maxson=tot[edge[i].v],son[now]=edge[i].v;
}
return tot[now];
}
void dfs2(int now,int topf)
{
idx[now]=++cnt;
a[cnt]=b[now];
top[now]=topf;
if(!son[now]) return ;
dfs2(son[now],topf);
for(int i=head[now];i!=-;i=edge[i].nxt)
if(!idx[edge[i].v])
dfs2(edge[i].v,edge[i].v);
}
void Build(int k,int ll,int rr)
{
T[k].l=ll;T[k].r=rr;T[k].siz=rr-ll+;
if(ll==rr)
{
T[k].w=a[ll];
return ;
}
int mid=(ll+rr)>>;
Build(ls,ll,mid);
Build(rs,mid+,rr);
update(k);
}
void IntervalAdd(int k,int ll,int rr,int val)
{
if(ll<=T[k].l&&T[k].r<=rr)
{
T[k].w+=T[k].siz*val;
T[k].f+=val;
return ;
}
PushDown(k);
int mid=(T[k].l+T[k].r)>>;
if(ll<=mid) IntervalAdd(ls,ll,rr,val);
if(rr>mid) IntervalAdd(rs,ll,rr,val);
update(k);
}
int IntervalAsk(int k,int ll,int rr)
{
int ans=;
if(ll<=T[k].l&&T[k].r<=rr)
{
ans+=T[k].w;
return ans;
}
PushDown(k);
int mid=(T[k].l+T[k].r)>>;
if(ll<=mid) ans+=IntervalAsk(ls,ll,rr);
if(rr>mid) ans+=IntervalAsk(rs,ll,rr);
return ans;
}
int TreeSum(int x,int y)
{
int ans=;
while(top[x]!=top[y])//不在同一条链内
{
if(deep[top[x]]<deep[top[y]]) swap(x,y);
ans+=IntervalAsk(,idx[top[x]],idx[x]);
x=fa[top[x]];
}
if(deep[x]>deep[y]) swap(x,y);
if(x==y) return ans;
ans+=IntervalAsk(,idx[x]+,idx[y]);//需要修改的地方
return ans;
}
void TreeAdd(int x,int y)
{
while(top[x]!=top[y])//不在同一条链内
{
if(deep[top[x]]<deep[top[y]]) swap(x,y);
IntervalAdd(,idx[top[x]],idx[x],);
x=fa[top[x]];
}
if(deep[x]>deep[y]) swap(x,y);
if(x==y) return ;
IntervalAdd(,idx[x]+,idx[y],);//需要修改的地方
}
int main()
{
#ifdef WIN32
freopen("a.in","r",stdin);
#else
#endif
memset(head,-,sizeof(head));
int N=read(),M=read();
for(int i=;i<=N-;i++)
{
int x=read(),y=read();
AddEdge(x,y);AddEdge(y,x);
}
dfs1(root,,);
dfs2(root,root);
Build(,,N);
while(M--)
{
char opt[];int x,y;
scanf("%s",opt);x=read();y=read();
if(opt[]=='P')
TreeAdd(x,y);
else
printf("%d\n",TreeSum(x,y)); }
return ;
}
洛谷P3038 [USACO11DEC]牧草种植Grass Planting的更多相关文章
- 洛谷 P3038 [USACO11DEC]牧草种植Grass Planting
题目描述 Farmer John has N barren pastures (2 <= N <= 100,000) connected by N-1 bidirectional road ...
- 洛谷 P3038 [USACO11DEC]牧草种植Grass Planting(树链剖分)
题解:仍然是无脑树剖,要注意一下边权,然而这种没有初始边权的题目其实和点权也没什么区别了 代码如下: #include<cstdio> #include<vector> #in ...
- P3038 [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 ...
- 树链剖分【p3038】[USACO11DEC]牧草种植Grass Planting
表示看不太清. 概括题意 树上维护区间修改与区间和查询. 很明显树剖裸题,切掉,细节处错误T了好久 TAT 代码 #include<cstdio> #include<cstdlib& ...
- [USACO11DEC]牧草种植Grass Planting
图很丑.明显的树链剖分,需要的操作只有区间修改和区间查询.不过这里是边权,我们怎么把它转成点权呢?对于E(u,v),我们选其深度大的节点,把边权扔给它.因为这是树,所以每个点只有一个父亲,所以每个边权 ...
- 【LuoguP3038/[USACO11DEC]牧草种植Grass Planting】树链剖分+树状数组【树状数组的区间修改与区间查询】
模拟题,可以用树链剖分+线段树维护. 但是学了一个厉害的..树状数组的区间修改与区间查询.. 分割线里面的是转载的: ----------------------------------------- ...
- 洛谷P3038 牧草种植Grass Planting
思路: 首先,这道题的翻译是有问题的(起码现在是),查询的时候应该是查询某一条路径的权值,而不是某条边(坑死我了). 与平常树链剖分题目不同的是,这道题目维护的是边权,而不是点权,那怎么办呢?好像有点 ...
- 洛谷P3038 牧草种植 [树链剖分]
题目传送门 牧草种植 题目描述 Farmer John has N barren pastures (2 <= N <= 100,000) connected by N-1 bidirec ...
随机推荐
- Mycat入门
1. Mycat入门 官网 http://www.mycat.io/ 1.1. 什么是Mycat 一个彻底开源的,面向企业应用开发的大数据库集群 支持事务.ACID.可以替代MySQL的加强版数据库 ...
- git使用方法----如何利用git管理代码?如何使用git将代码传到github中去
## 在文件夹中打开 git here; 1.git init ===初始化一个仓库(这个仓库会存放,git对我们代码进行备份的文件)2.配置个人信息 -- --在git中设置当前使用的用户是==( ...
- Ubantu linux中使用PyCharm之---破解PyCharm,实现永久免费试用
打开 http://idea.lanyus.com/ 这个网址,可以直接复制到浏览器打开 获取注册码 K71U8DBPNE-eyJsaWNlbnNlSWQiOiJLNzFVOERCUE5FIiwibG ...
- json_decode与json_encode容易被忽视的点
一.json_decode的使用,json_decode共有4个参数 json_decode ( string $json [, bool $assoc=FALSE [, int $depth= 51 ...
- 【Guava】使用Guava的RateLimiter做限流
一.常见的限流算法 目前常用的限流算法有两个:漏桶算法和令牌桶算法. 1.漏桶算法 漏桶算法的原理比较简单,请求进入到漏桶中,漏桶以一定的速率漏水.当请求过多时,水直接溢出.可以看出,漏桶算法可以强制 ...
- sql server 备份与恢复系列一 必备知识
一.备份概述 数据安全是数据库的生命,数据库在使用过程中难免会遇到如:使用者的误操作或是被恶意修改,硬件故障导致数据文件无法被访问,自然灾害导致机房在物理上的损毁.本章从备份与恢复的功能作为解决问题的 ...
- hd1007
#include <iostream> #include <algorithm> #include <cmath> using namespace std; str ...
- java 中文乱码的解决方法
1. 这方法行之有效,但是谨慎用,它会作用服务器.超链接中带有的中文字符,<a class="add" href = "system/showDataAdd.act ...
- 【数据科学】Python数据可视化概述
注:很早之前就打算专门写一篇与Python数据可视化相关的博客,对一些基本概念和常用技巧做一个小结.今天终于有时间来完成这个计划了! 0. Python中常用的可视化工具 Python在数据科学中的地 ...
- 【原创】关于Git暂存区的理解
关于Git暂存区的理解 暂存区可以说是Git的三大重要的区域之一,另外两个分别是工作目录和Git仓库,所以说对暂存区的深入理解可以帮助我们理解很多Git命令背后隐藏的工作原理.今天,本文将以 ...