题目大意:
有一棵结点个数为n的树,有m个操作,可以将一段路径上每条边的权值+1或询问某一个边的权值。

思路:
树链剖分+线段树。
轻重链划分本身比较简单,主要需要思考如何用线段树维护每条链。
当x,y不在同一条链上时,先处理深度大的链,对于每一个链,建立一棵动态开点的线段树,用一个数组len顺序记录每一条边在链中的编号,然后维护len[x]+1到len[top[x]]这一区间的权值即可。
处理轻边时,可以直接用一个数组保存它的权值。
因为轻重边肯定是交替的,因此每次循环都可以先维护一个重边,再维护一个轻边。
最后x和y肯定会跳到同一条重链上,这时候我们只要维护这条链上从len[x]+1到len[y]的边权即可(实际上就是一个找LCA的过程)。
询问则比较简单,因为询问的是一条边而非一条路径,因此直接分类讨论这条边是轻边还是重边即可。(网上那么多题解都是没有读题吗?)

细节:
轻边不能直接对边上某一点开线段树维护,因为如果这个点刚好是某一个重链的第一个点,就会出现轻重边共用同一棵线段树的情况。
这题是USACO月赛题,官方题解是用树状数组维护,但是他们是对整棵树开树状数组,所以还是没我跑得快。

 #include<cstdio>
#include<cctype>
#include<vector>
inline int getint() {
char ch;
while(!isdigit(ch=getchar()));
int x=ch^'';
while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
return x;
}
const int V=;
std::vector<int> e[V];
inline void add_edge(const int u,const int v) {
e[u].push_back(v);
}
class SegmentTree {
private:
int val[V<<],left[V<<],right[V<<];
int sz;
int newnode() {
return ++sz;
}
public:
int root[V];
void modify(int &p,const int b,const int e,const int l,const int r) {
if(!p) p=newnode();
if((b==l)&&(e==r)) {
val[p]++;
return;
}
int mid=(b+e)>>;
if(l<=mid) modify(left[p],b,mid,l,std::min(mid,r));
if(r>mid) modify(right[p],mid+,e,std::max(mid+,l),r);
}
int query(int &p,const int b,const int e,const int x) {
if(!p) return ;
if(b==e) return val[p];
int mid=(b+e)>>;
return (x<=mid?query(left[p],b,mid,x):query(right[p],mid+,e,x))+val[p];
}
};
SegmentTree t;
int size[V],son[V],top[V],len[V],dep[V],par[V];
void dfs1(const int x,const int p) {
size[x]=;
dep[x]=dep[p]+;
par[x]=p;
for(unsigned i=;i<e[x].size();i++) {
int &y=e[x][i];
if(y==p) continue;
dfs1(y,x);
size[x]+=size[y];
if(size[y]>size[son[x]]) son[x]=y;
}
}
void dfs2(const int x) {
top[x]=(x==son[par[x]])?top[par[x]]:x;
for(unsigned i=;i<e[x].size();i++) {
int &y=e[x][i];
if(y==par[x]) continue;
dfs2(y);
len[x]=len[son[x]]+;
}
}
int val[V];
inline void modify(int x,int y) {
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
if(x!=top[x]) t.modify(t.root[top[x]],,len[top[x]],len[x]+,len[top[x]]);
val[top[x]]++;
x=par[top[x]];
}
if(x==y) return;
if(dep[x]<dep[y]) std::swap(x,y);
t.modify(t.root[top[x]],,len[top[x]],len[x]+,len[y]);
}
inline int query(int x,int y) {
if(dep[x]<dep[y]) std::swap(x,y);
return top[x]==top[y]?t.query(t.root[top[x]],,len[top[x]],len[y]):val[x];
}
int main() {
int n=getint(),m=getint();
for(int i=;i<n;i++) {
int u=getint(),v=getint();
add_edge(u,v);
add_edge(v,u);
}
dfs1(,);
dfs2();
while(m--) {
char op[];
scanf("%s",op);
int x=getint(),y=getint();
if(op[]=='P') {
modify(x,y);
}
else {
printf("%d\n",query(x,y));
}
}
return ;
}

[USACO11DEC]Grass Planting的更多相关文章

  1. [USACO11DEC] Grass Planting (树链剖分)

    题目描述 Farmer John has N barren pastures (2 <= N <= 100,000) connected by N-1 bidirectional road ...

  2. USACO Grass Planting

    洛谷 P3038 [USACO11DEC]牧草种植Grass Planting 洛谷传送门 JDOJ 2282: USACO 2011 Dec Gold 3.Grass Planting JDOJ传送 ...

  3. spoj - Grass Planting(树链剖分模板题)

    Grass Planting 题意 给出一棵树,树有边权.每次给出节点 (u, v) ,有两种操作:1. 把 u 到 v 路径上所有边的权值加 1.2. 查询 u 到 v 的权值之和. 分析 如果这些 ...

  4. 洛谷P3038 [USACO11DEC]牧草种植Grass Planting

    题目描述 Farmer John has N barren pastures (2 <= N <= 100,000) connected by N-1 bidirectional road ...

  5. AC日记——[USACO11DEC]牧草种植Grass Planting 洛谷 P3038

    题目描述 Farmer John has N barren pastures (2 <= N <= 100,000) connected by N-1 bidirectional road ...

  6. 洛谷 P3038 [USACO11DEC]牧草种植Grass Planting

    题目描述 Farmer John has N barren pastures (2 <= N <= 100,000) connected by N-1 bidirectional road ...

  7. P3038 [USACO11DEC]牧草种植Grass Planting

    题目描述 Farmer John has N barren pastures (2 <= N <= 100,000) connected by N-1 bidirectional road ...

  8. 洛谷 P3038 [USACO11DEC]牧草种植Grass Planting(树链剖分)

    题解:仍然是无脑树剖,要注意一下边权,然而这种没有初始边权的题目其实和点权也没什么区别了 代码如下: #include<cstdio> #include<vector> #in ...

  9. [USACO11DEC]牧草种植Grass Planting

    图很丑.明显的树链剖分,需要的操作只有区间修改和区间查询.不过这里是边权,我们怎么把它转成点权呢?对于E(u,v),我们选其深度大的节点,把边权扔给它.因为这是树,所以每个点只有一个父亲,所以每个边权 ...

随机推荐

  1. Python标准库笔记(6) — struct模块

    该模块作用是完成Python数值和C语言结构体的Python字符串形式间的转换.这可以用于处理存储在文件中或从网络连接中存储的二进制数据,以及其他数据源. 用途: 在Python基本数据类型和二进制数 ...

  2. 2018ICPC南京网络赛

    2018ICPC南京网络赛 A. An Olympian Math Problem 题目描述:求\(\sum_{i=1}^{n} i\times i! \%n\) solution \[(n-1) \ ...

  3. HDU 6196 happy happy happy 爆搜加剪枝

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6196 题意:给你长度为n的序列,爸爸和儿子玩一个游戏,儿子先手,儿子每次都选择最左边与最右边最大的那个 ...

  4. unity 代码有调整,重新导出 iOS 最烦的就是 覆盖导出后项目不能打开

    unity  代码有调整,重新导出 iOS 最烦的就是 覆盖导出后项目不能打开,原因是 editor 里面的脚本,破坏了 Unity-iPhone.xcodeproj 里面的结构,具体是什么原因,也不 ...

  5. jdbc一次性采集mysql和oracle的海量数据,5000W+为例

    最近做的采集工具遇到采集一天数据(超过5000W行数据)的情况, 采集mysql的时候直接采用流式读取的方式可以一次全部都读取出来,速度的话取决于网络速度 stmt = conn.createStat ...

  6. Python访问MySQL(1):初步使用PyMySQL包

    Windows 10家庭中文版,MySQL 5.7.20 for Win 64,Python 3.6.4,PyMySQL 0.8.1,2018-05-08 ---- 使用Python访问MySQL数据 ...

  7. js面试题之求数组最值

    今天继续分享js常见的面试题,求数组最大值,最小值,这里列举4种常见解法,还有其他方法也可以实现,读者知道可以私信我,我将把意见列举到博客中,欢迎提出意见. 第一种,利用数组排序 var arr=[3 ...

  8. No.11 selenium学习之路之加载浏览器插件for Firefox

    打开帮助 —— 故障排除信息

  9. python+selenium第一步 - 环境搭建

    刚开始学习一门技术,肯定是要从环境搭建开始的,我也不例外. 首先选择需要安装的版本,我使用的是mac自带的2.7版本. selenium2,和火狐浏览器 为求稳定不会出现未知问题,我选择了seleni ...

  10. Java 容器的基本概念

    java容器类类库的用途时"保存对象",并将其划分为两个不同的概念: 1)Collection(采集).一个独立元素的序列,这些元素都服从一条或多条规则,List必须按照插入的顺序 ...