题目

Link

分析

典型的树链剖分题,

树链剖分学习资料

Code

#include <bits/stdc++.h>

using namespace std;

const int maxn = 30000 + 131;
struct Edge {
int Next;
int To;
}edge[maxn<<1];
int Head[maxn], tot, n;
///以下是重链数据定义
int top[maxn]; //重链的顶点
int deep[maxn]; //树上节点的深度
int Pre[maxn]; //父节点
int size[maxn]; //子树节点大小
int son[maxn]; //重链中节点的子节点
///以下有关离散到线段树数据定义
int t_s[maxn]; //树上的点离散到线段树
int s_t[maxn]; //线段树映射回树上的点。
int pos;
//题目数据
int w[maxn]; void INIT() {
tot = pos = 0;
memset(son, -1, sizeof(son));
memset(Head,-1, sizeof(Head));
}
////
void Addedge(int from, int to) {
edge[tot].To = to;
edge[tot].Next = Head[from];
Head[from] = tot++;
} void Getlist(int root, int pre, int d) { //获得重链
deep[root] = d;
Pre[root] = pre;
size[root] = 1;
for(int i = Head[root]; ~i; i = edge[i].Next) {
int v = edge[i].To;
if(v != pre) {
Getlist(v, root, d+1);
size[root] += size[v]; //累加size
if(son[root] == -1 || size[son[root]] < size[v])
son[root] = v; //更新重链子节点
}
}
}
////离散点到线段树上
void Lisan_TtoS(int u, int root) {
top[u] = root;
t_s[u] = ++pos;
s_t[t_s[u]] = u;
if(son[u] == -1) return ;
Lisan_TtoS(son[u], root); for(int i = Head[u]; ~i; i = edge[i].Next) {
int v = edge[i].To;
if(v != son[u] && v != Pre[u])
Lisan_TtoS(v,v); //新的重链开始.
}
}
////线段树
int Sum[maxn << 2];
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1 void PushUp(int rt) {
Sum[rt] = Sum[rt<<1] + Sum[rt<<1|1];
} void Build(int l, int r, int rt) {
if(l == r) {
Sum[rt] = w[s_t[l]];
/*cout << "This is tree idx:" << s_t[l] \
<< " values:" << w[s_t[l]] << endl;*/
return ;
}
int m = (l + r) >> 1;
Build(lson);
Build(rson);
PushUp(rt);
} void Update(int pos, int val, int l, int r, int rt) {
if(l == r) {
Sum[rt] = val;
//cout << "This is the tree id: " << s_t[l] << endl;
return ;
}
int m = (l + r) >> 1;
if(pos <= m) Update(pos, val, lson);
else Update(pos, val, rson);
PushUp(rt);
} int Query(int L, int R, int l, int r, int rt) {
//cout << "seg l : " << l << " r : " << r ;
//cout << " Find L:" << L << " R: " << R << endl;
if(L <= l && r <= R) {
//cout << "Had add : " << Sum[rt] << endl;
return Sum[rt];
}
int m = (l + r) >> 1;
int ret = 0;
if(L <= m) ret += Query(L, R, lson);
if(R > m) ret += Query(L, R, rson);
return ret;
}
////查询(u,v)
int Find(int u, int v) { /// u to v
int fa_u = top[u]; /// u总是更深的点.
int fa_v = top[v];
int ret = 0;
while(fa_u != fa_v) {
if(deep[fa_u] < deep[fa_v]) {
swap(u, v);
swap(fa_v,fa_u);
}
//cout << "This is the list :" << fa_u << "->" << u << endl;
//cout << "This is the Segm :" << t_s[fa_u] << "->" << t_s[u] << endl;
ret += Query(t_s[fa_u], t_s[u], 1, n, 1);
u = Pre[fa_u];
fa_u = top[u];
}
// 点, 所以会有两点重合的情况。
// 边的处理, 可以理解 i 点 to j 点的边 v 就是 j 点的权值
// root 处理为最小只即可 or (0) or 各种适合值。
if(deep[u] > deep[v]) swap(u, v);
ret += Query(t_s[u], t_s[v], 1, n, 1);
return ret;
} int main() {
int T;
scanf("%d",&T);
for(int kase = 1; kase <= T; ++kase) {
scanf("%d",&n);
INIT();
for(int i = 1; i <= n; ++i)
scanf("%d",w+i);
int u, v;
for(int i = 1; i < n; ++i) {
scanf("%d%d",&u, &v);
u++, v++;
Addedge(u, v);
Addedge(v, u);
}
Getlist(1, -1, 0);
Lisan_TtoS(1,1);
Build(1, n, 1);
printf("Case %d:\n",kase);
int q;
scanf("%d",&q);
for(int i = 0; i < q; ++i) {
int op;
scanf("%d%d%d",&op,&u,&v);
if(op == 1) {
Update(t_s[++u], v, 1, n, 1);
}
else {
u++, v++;
printf("%d\n", Find(u, v));
}
}
}
return 0;
}

LightOJ 1348 (树链剖分 + 线段树(树状数组))的更多相关文章

  1. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  2. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  3. BZOJ2243 (树链剖分+线段树)

    Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...

  4. POJ3237 (树链剖分+线段树)

    Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...

  5. bzoj4034 (树链剖分+线段树)

    Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...

  6. HDU4897 (树链剖分+线段树)

    Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...

  7. Aizu 2450 Do use segment tree 树链剖分+线段树

    Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...

  8. 【POJ3237】Tree(树链剖分+线段树)

    Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...

  9. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

随机推荐

  1. SSM项目使用GoEasy 获取客户端上下线实时状态变化及在线客户列表

    一.背景 上篇SSM项目使用GoEasy 实现web消息推送服务是GoEasy的一个用途,今天我们来看GoEasy的第二个用途:订阅客户端上下线实时状态变化.获取当前在线客户数量和在线客户列表.截止我 ...

  2. mysql-笔记-默认值

    1 指定列的默认值 columnName int default '-1' 2 integer 列-设置自增列 也是指定默认值的方式 3 默认值必须是常量 不能使用函数.表达式---特例:timest ...

  3. sql中检查时间是否重叠

    先画一个时间轴,方便理解. 设新的时间块,开始时间为@BeginDate,结束时间为@EndDate.数据库中的数据为BeginDate和EndDate 这样可以直观的看出来,新的时间块插入进来,只需 ...

  4. cocos 资源工作流程

    前面的话 本文将详细介绍 cocos 中的资源工作流程 概述 [同步性] 资源管理器中的资源和操作系统的文件管理器中看到的项目资源文件夹是同步的 在资源管理器中对资源的移动.重命名和删除,都会直接在用 ...

  5. 内存溢出OOM

    如何避免OOM 异常? 想要避免OOM 异常首先我们要知道什么情况下会导致OOM 异常. 1.图片过大导致OOM Android 中用bitmap 时很容易内存溢出,比如报如下错误:Java.lang ...

  6. Go语言中Loop的注意点

    Go语言和其他语言不一样,它只有一种循环方式,就是for语句 可以参考如下公式: for initialisation; condition; post{ //Do Something } 执行顺序 ...

  7. Flask 构建微电影视频网站(五)

    基于角色的访问控制 权限管理 class AuthForm(FlaskForm): name = StringField( label='权限', validators=[ DataRequired( ...

  8. <数据结构基础学习>(五)递归

    一. 递归 本质上,将原来的问题,转化为更小的同样的问题 举例:数组求和 Sum(arr[0... n-1]) = arr[0] + Sum(arr[1...n-1])  第二部分为更小的同一个问题 ...

  9. 集合源码分析[2]-AbstractList 源码分析

    AbstractList 类型:抽象类 接口的继承以及实现关系 继承AbstractCollection 实现List接口 典型方法实现解析 public List<E> subList( ...

  10. Java集合的总结

    参考博客: http://www.jianshu.com/p/63e76826e852 http://www.cnblogs.com/LittleHann/p/3690187.html https:/ ...