题目

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. 【刷题】Git知识点

    参考:学习总结之Git学习-总 1-origin是什么? 答:origin 是默认的远程版本库名称,可以在 .git/config 之中进行修改.在默认情况下,origin指向的就是你本地的代码库托管 ...

  2. Net包管理NuGet(3)搭建私服及引用私服的包

    1,打开vs创建项目(ASP.NET WEB空项目)假设命名为MyNuGet 空项目解决方案如图 2,右键引用>管理NuGet程序包>切到浏览搜索NuGet.Server然后安装(3.1. ...

  3. stream流操作List工具类

    工作中操作List对于程序猿来说是"基本操作",为了更加便利,对JDK8的新特性stream流进行二次封装.话不多说,直接上代码 package com.mydemo; impor ...

  4. DAY25、面向对象总复习

    面向对象总复习:面向过程编程思想: 核心是 过程 二字, 过程指的是解决问题的步骤是,即先干什么再干什么. 基于该编程思想编写程序,相当于一条流水线,一种机械式的思维方式. 面向对象编程思想: 核心是 ...

  5. mpvue——Error: Cannot find module 'escape-string-regexp'

    报错 $ cnpm run build > mpvue-qq@1.0.0 build D:\wamp\www\wxsmallsoft\mini-0212\mpvueQQ > node bu ...

  6. python爬虫基础应用----爬取校花网视频

    一.爬虫简单介绍 爬虫是什么? 爬虫是首先使用模拟浏览器访问网站获取数据,然后通过解析过滤获得有价值的信息,最后保存到到自己库中的程序. 爬虫程序包括哪些模块? python中的爬虫程序主要包括,re ...

  7. Springboot文件上传与下载

    一.创建简单的springboot-web项目 二.文件上传属性配置 #默认支持文件上传 spring.http.multipart.enabled =true spring.http.multipa ...

  8. 【转】Java 线程池

    什么是线程池? 线程池是指在初始化一个多线程应用程序过程中创建一个线程集合,然后在需要执行新的任务时重用这些线程而不是新建一个线程.线程池中线程的数量通常完全取决于可用内存数量和应用程序的需求.然而, ...

  9. react 16 ssr的重构踩坑

    ssr 服务端不能识别前端的window.特别是首屏渲染的数据需要用到window对象(比如href += location.search); 服务端不能加载图片,css文件. require.ext ...

  10. spring boot下使用logback或log4j生成符合Logstash标准的JSON格式

    spring boot下使用logback或log4j生成符合Logstash标准的JSON格式 一.依赖 由于配置中使用了json格式的日志输出,所以需要引入如下依赖 "net.logst ...