POJ 3237:Tree(树链剖分)
http://poj.org/problem?id=3237
题意:树链剖分。操作有三种:改变一条边的边权,将 a 到 b 的每条边的边权都翻转(即 w[i] = -w[i]),询问 a 到 b 的最大边权。
思路:一开始没有用区间更新,每次翻转的时候都更新到叶子节点,居然也能过,后来看别人的发现也是可以区间更新的。
第一种:无区间更新水过
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
#define N 100010
#define INF -0x7fffffff
#define lson rt<<1, l, m
#define rson rt<<1|1, m + 1, r
struct node
{
int v, w, next;
}edge[N*];
int top[N], size[N], dep[N], son[N], fa[N], tid[N], time;
int tot, head[N], e[N][];
int tree[N<<]; void init()
{
memset(head, -, sizeof(head));
memset(son, -, sizeof(son));
time = tot = ;
} void add(int u, int v, int w)
{
edge[tot].v = v; edge[tot].next = head[u]; edge[tot].w = w; head[u] = tot++;
} void dfs1(int u, int f, int d)
{
size[u] = ;
dep[u] = d;
fa[u] = f;
for(int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].v;
if(v == f) continue;
dfs1(v, u, d + );
size[u] += size[v];
if(son[u] == - || size[son[u]] < size[v]) son[u] = v;
}
} void dfs2(int u, int tp)
{
top[u] = tp;
tid[u] = ++time;
if(son[u] == -) return ;
dfs2(son[u], tp);
for(int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].v;
if(v != son[u] && v != fa[u])
dfs2(v, v);
}
} void pushup(int rt)
{
tree[rt] = max(tree[rt<<], tree[rt<<|]);
} void build(int rt, int l, int r)
{
tree[rt] = ;
if(l == r) return ;
int m = (l + r) >> ;
build(lson); build(rson);
} void update(int rt, int l, int r, int id, int w) // 更新边
{
if(l == r && l == id) {
tree[rt] = w;
return ;
}
if(l == r) return ;
int m = (l + r) >> ;
if(id <= m) update(lson, id, w);
else update(rson, id, w);
pushup(rt);
} void Update(int rt, int l, int r, int L, int R) // 翻转值
{
if(l == r && L <= l && r <= R) {
tree[rt] = -tree[rt];
return ;
}
if(l == r) return ;
int m = (l + r) >> ;
if(L <= m) Update(lson, L, R);
if(R > m) Update(rson, L, R);
pushup(rt);
} int query(int rt, int l, int r, int L, int R)
{
int ans = INF;
if(L <= l && r <= R) {
ans = max(ans, tree[rt]);
return ans;
}
int m = (l + r) >> ;
if(L <= m) ans = max(ans, query(lson, L, R));
if(m < R) ans = max(ans, query(rson, L, R));
return ans;
} int change(int u, int v) // 查询 (u, v) 最长距离
{
int ans = INF;
while(top[u] != top[v]) {
if(dep[top[u]] < dep[top[v]]) swap(u, v);
ans = max(ans, query(, , time, tid[top[u]], tid[u]));
u = fa[top[u]];
}
if(u == v) return ans;
if(dep[u] > dep[v]) swap(u, v);
ans = max(ans, query(, , time, tid[son[u]], tid[v]));
return ans;
} void uuu(int u, int v) // 将值翻转
{
while(top[u] != top[v]) {
if(dep[top[u]] < dep[top[v]]) swap(u, v);
Update(, , time, tid[top[u]], tid[u]);
u = fa[top[u]];
}
if(u == v) return ;
if(dep[u] > dep[v]) swap(u, v);
Update(, , time, tid[son[u]], tid[v]);
} void debug()
{
printf("debug *************\n");
printf("%d\n", time);
for(int i = ; i <= time; i++) {
printf("%d, ", top[i]);
}
puts("");
} int main()
{
int t;
scanf("%d", &t);
while(t--) {
int n;
scanf("%d", &n);
init();
for(int i = ; i < n; i++) {
scanf("%d%d%d", &e[i][], &e[i][], &e[i][]);
add(e[i][], e[i][], e[i][]);
add(e[i][], e[i][], e[i][]);
}
dfs1(, , );
dfs2(, );
build(, , time);
for(int i = ; i < n; i++) {
if(dep[e[i][]] > dep[e[i][]]) swap(e[i][], e[i][]);
update(, , time, tid[e[i][]], e[i][]);
}
// for(int i = 1; i <= n; i++) printf("tid[%d] :%d\n", i, tid[i]);
char s[];
int a, b;
while(scanf("%s", s) == ) {
if(s[] == 'D') break;
scanf("%d%d", &a, &b);
if(s[] == 'Q') {
// puts("");
printf("%d\n", change(a, b));
// puts("");
} else if(s[] == 'N') {
uuu(a, b);
} else {
update(, , time, tid[e[a][]], b);
}
}
}
return ;
}
第二种:区间更新
比上一种快了一倍的时间。就是记录一个最大值和最小值,在翻转的时候,最大值 = -最小值, 最小值 = -最大值,每次标记取反。这样可以快速求出来。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
#define N 100010
#define INF 0x7fffffff
#define lson rt<<1, l, m
#define rson rt<<1|1, m + 1, r
struct node
{
int v, w, next;
}edge[N*];
int top[N], size[N], dep[N], son[N], fa[N], tid[N], time;
int tot, head[N], e[N][];
int col[N<<], Min[N<<], Max[N<<]; void init()
{
memset(head, -, sizeof(head));
memset(son, -, sizeof(son));
time = tot = ;
} void add(int u, int v, int w)
{
edge[tot].v = v; edge[tot].next = head[u]; edge[tot].w = w; head[u] = tot++;
} void dfs1(int u, int f, int d)
{
size[u] = ;
dep[u] = d;
fa[u] = f;
for(int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].v;
if(v == f) continue;
dfs1(v, u, d + );
size[u] += size[v];
if(son[u] == - || size[son[u]] < size[v]) son[u] = v;
}
} void dfs2(int u, int tp)
{
top[u] = tp;
tid[u] = ++time;
if(son[u] == -) return ;
dfs2(son[u], tp);
for(int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].v;
if(v != son[u] && v != fa[u])
dfs2(v, v);
}
} void pushup(int rt)
{
Min[rt] = min(Min[rt<<], Min[rt<<|]);
Max[rt] = max(Max[rt<<], Max[rt<<|]);
} void pushdown(int rt)
{
int tmp;
if(col[rt]) {
tmp = -Max[rt<<];
Max[rt<<] = -Min[rt<<];
Min[rt<<] = tmp; tmp = -Max[rt<<|];
Max[rt<<|] = -Min[rt<<|];
Min[rt<<|] = tmp; col[rt<<] ^= ;
col[rt<<|] ^= ;
col[rt] ^= ;
}
} void build(int rt, int l, int r)
{
Min[rt] = INF;
Max[rt] = -INF;
col[rt] = ;
if(l == r) return ;
int m = (l + r) >> ;
build(lson); build(rson);
} void update(int rt, int l, int r, int id, int w) // 更新边
{
if(l == r && l == id) {
Min[rt] = Max[rt] = w;
return ;
}
pushdown(rt);
int m = (l + r) >> ;
if(id <= m) update(lson, id, w);
else update(rson, id, w);
pushup(rt);
} void Update(int rt, int l, int r, int L, int R) // 翻转值
{
int tmp;
if(L <= l && r <= R) {
tmp = -Max[rt];
Max[rt] = -Min[rt];
Min[rt] = tmp;
col[rt] ^= ;
return ;
}
pushdown(rt);
int m = (l + r) >> ;
if(L <= m) Update(lson, L, R);
if(R > m) Update(rson, L, R);
pushup(rt);
} int query(int rt, int l, int r, int L, int R)
{
int ans = -INF;
if(L <= l && r <= R) {
ans = max(ans, Max[rt]);
return ans;
}
pushdown(rt);
int m = (l + r) >> ;
if(L <= m) ans = max(ans, query(lson, L, R));
if(m < R) ans = max(ans, query(rson, L, R));
return ans;
} int change(int u, int v) // 查询 (u, v) 最长距离
{
int ans = -INF;
while(top[u] != top[v]) {
if(dep[top[u]] < dep[top[v]]) swap(u, v);
ans = max(ans, query(, , time, tid[top[u]], tid[u]));
u = fa[top[u]];
}
if(u == v) return ans;
if(dep[u] > dep[v]) swap(u, v);
ans = max(ans, query(, , time, tid[son[u]], tid[v]));
return ans;
} void uuu(int u, int v) // 将值翻转
{
while(top[u] != top[v]) {
if(dep[top[u]] < dep[top[v]]) swap(u, v);
Update(, , time, tid[top[u]], tid[u]);
u = fa[top[u]];
}
if(u == v) return ;
if(dep[u] > dep[v]) swap(u, v);
Update(, , time, tid[son[u]], tid[v]);
} int main()
{
int t;
scanf("%d", &t);
while(t--) {
int n;
scanf("%d", &n);
init();
for(int i = ; i < n; i++) {
scanf("%d%d%d", &e[i][], &e[i][], &e[i][]);
add(e[i][], e[i][], e[i][]);
add(e[i][], e[i][], e[i][]);
}
dfs1(, , );
dfs2(, );
build(, , time);
for(int i = ; i < n; i++) {
if(dep[e[i][]] > dep[e[i][]]) swap(e[i][], e[i][]);
update(, , time, tid[e[i][]], e[i][]);
}
char s[];
int a, b;
while(scanf("%s", s) == ) {
if(s[] == 'D') break;
scanf("%d%d", &a, &b);
if(s[] == 'Q') {
printf("%d\n", change(a, b));
} else if(s[] == 'N') {
uuu(a, b);
} else {
update(, , time, tid[e[a][]], b);
}
}
}
return ;
} /*
1 3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
NEGATE 1 3
QUERY 1 3
DONE
*/
POJ 3237:Tree(树链剖分)的更多相关文章
- poj 3237 Tree 树链剖分
题目链接:http://poj.org/problem?id=3237 You are given a tree with N nodes. The tree’s nodes are numbered ...
- POJ 3237 Tree (树链剖分 路径剖分 线段树的lazy标记)
题目链接:http://poj.org/problem?id=3237 一棵有边权的树,有3种操作. 树链剖分+线段树lazy标记.lazy为0表示没更新区间或者区间更新了2的倍数次,1表示为更新,每 ...
- POJ 3237.Tree -树链剖分(边权)(边值更新、路径边权最值、区间标记)贴个板子备忘
Tree Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 12247 Accepted: 3151 Descriptio ...
- poj 3237 Tree 树链剖分+线段树
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
- poj 3237 Tree(树链拆分)
题目链接:poj 3237 Tree 题目大意:给定一棵树,三种操作: CHANGE i v:将i节点权值变为v NEGATE a b:将ab路径上全部节点的权值变为相反数 QUERY a b:查询a ...
- POJ3237 Tree 树链剖分 边权
POJ3237 Tree 树链剖分 边权 传送门:http://poj.org/problem?id=3237 题意: n个点的,n-1条边 修改单边边权 将a->b的边权取反 查询a-> ...
- Hdu 5274 Dylans loves tree (树链剖分模板)
Hdu 5274 Dylans loves tree (树链剖分模板) 题目传送门 #include <queue> #include <cmath> #include < ...
- Query on a tree——树链剖分整理
树链剖分整理 树链剖分就是把树拆成一系列链,然后用数据结构对链进行维护. 通常的剖分方法是轻重链剖分,所谓轻重链就是对于节点u的所有子结点v,size[v]最大的v与u的边是重边,其它边是轻边,其中s ...
- 【BZOJ-4353】Play with tree 树链剖分
4353: Play with tree Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 31 Solved: 19[Submit][Status][ ...
- SPOJ Query on a tree 树链剖分 水题
You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...
随机推荐
- jQuery基础修炼圣典—DOM篇(一)
一.DOM节点的创建 1.创建节点及节点属性 通过JavaScript可以很方便的获取DOM节点,从而进行一系列的DOM操作.但实际上一般开发者都习惯性的先定义好HTML结构,但这样就非常不灵活了. ...
- Java静态代码分析工具——FindBugs插件的安装与使用
1 什么是FindBugs FindBugs 是一个静态分析工具,它检查类或者 JAR 文件,将字节码与一组缺陷模式进行对比以发现可能的问题.有了静态分析工具,就可以在不实际运行程序的情况对软件进行分 ...
- 面向对象编程(九)——面向对象三大特性之继承以及重写、Object类的介绍
面向对象三大特性 面向对象三大特征:继承 :封装/隐藏 :多态(为了适应需求的多种变化,使代码变得更加通用!) 封装:主要实现了隐藏细节,对用户提供访问接口,无需关心方法的具体实现. 继承:很好的实现 ...
- 前端学习——css基础知识,选择器与html模板、值得收藏的html标签
一.css需要的html(采用html5标准) DTD,文档类型声明: <!Doctype html> 文本编码声明: <meta charset="utf-8" ...
- 自动检查点(Automatic Checkpointing)
自动检查点(Automatic Checkpointing)在oracle10g,支持自动检查点调优,这样可以提高系统可用性.自动检查点调优需要开启参数fast_start_mttr_target. ...
- NSDictionary
// ------------------------------字典------------------------------------------------- NSDictionary *d ...
- 怎么查找执行比较慢的sql语句-DBA给的建议
1.使用sql动态视图 如下: b.text,a.total_worker_time,a.total_logical_reads,a.total_elapsed_time,execution_coun ...
- redhat vim编辑器永久添加行号
cd ~ vim .vimrc 第一行加入: set nu :wq 保存退出,即可 如果想取消设置,同理删除set nu即可
- PostgreSQL Replication之第十二章 与Postgres-XC一起工作(3)
12.3 配置一个简单的集群 在本章中,我们要建立一个由三个数据节点组成的集群.一个协调节点,以及管理集群的全局事务管理节点.对于每个组件,我们必须创建一个目录: hs@vm:~/data$ ls - ...
- Leetcode: Self Crossing
You are given an array x of n positive numbers. You start at point (0,0) and moves x[0] metres to th ...