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(树链剖分)的更多相关文章

  1. poj 3237 Tree 树链剖分

    题目链接:http://poj.org/problem?id=3237 You are given a tree with N nodes. The tree’s nodes are numbered ...

  2. POJ 3237 Tree (树链剖分 路径剖分 线段树的lazy标记)

    题目链接:http://poj.org/problem?id=3237 一棵有边权的树,有3种操作. 树链剖分+线段树lazy标记.lazy为0表示没更新区间或者区间更新了2的倍数次,1表示为更新,每 ...

  3. POJ 3237.Tree -树链剖分(边权)(边值更新、路径边权最值、区间标记)贴个板子备忘

    Tree Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 12247   Accepted: 3151 Descriptio ...

  4. poj 3237 Tree 树链剖分+线段树

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

  5. poj 3237 Tree(树链拆分)

    题目链接:poj 3237 Tree 题目大意:给定一棵树,三种操作: CHANGE i v:将i节点权值变为v NEGATE a b:将ab路径上全部节点的权值变为相反数 QUERY a b:查询a ...

  6. POJ3237 Tree 树链剖分 边权

    POJ3237 Tree 树链剖分 边权 传送门:http://poj.org/problem?id=3237 题意: n个点的,n-1条边 修改单边边权 将a->b的边权取反 查询a-> ...

  7. Hdu 5274 Dylans loves tree (树链剖分模板)

    Hdu 5274 Dylans loves tree (树链剖分模板) 题目传送门 #include <queue> #include <cmath> #include < ...

  8. Query on a tree——树链剖分整理

    树链剖分整理 树链剖分就是把树拆成一系列链,然后用数据结构对链进行维护. 通常的剖分方法是轻重链剖分,所谓轻重链就是对于节点u的所有子结点v,size[v]最大的v与u的边是重边,其它边是轻边,其中s ...

  9. 【BZOJ-4353】Play with tree 树链剖分

    4353: Play with tree Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 31  Solved: 19[Submit][Status][ ...

  10. SPOJ Query on a tree 树链剖分 水题

    You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...

随机推荐

  1. Demo4 Slides.js的使用

    Slides.js挺好用的啊,把示例中的Demo调试通了.首先把css.img.js文件夹下的内容全部拷贝到Vs网站项目下的Scripts文件夹下. 代码主要修改了一些图片路径和网址链接. <! ...

  2. MongoDB Map Reduce

    介绍 Map-Reduce是一种计算模型,简单的说就是将大批量的工作分解(MAP)执行,然后再将结果合并成最终结果(REDUCE). MongoDB提供的Map-Reduce非常灵活,对于大规模数据分 ...

  3. 安装Cocoapods(Pods 管理iOS 第三方库)

    安装 可先检测Mac电脑是否安装Pods.打开控制台: $ which pod 如果安装,结果如下;如果没有安装,控制台无反应. /usr/bin/pod 如果没有安装, 以下命令安装之. $ sud ...

  4. Tigase Server Clustering

    首先,在服务器上启用集群 修改init.properties --cluster-mode=true 自定义端口 允许自定义,但是所有的实例都要使用相同的端口,以便通讯 --cl-comp-ports ...

  5. apache allow和deny

    转自 http://www.cnblogs.com/top5/archive/2009/09/22/1571709.html 影响最终判断结果的只有两点: 1. order语句中allow.deny的 ...

  6. Android 开发环境搭建以及编译

    两种搭建编译环境的方式,一种方法是用户安装虚拟机,然后安装基础的Ubuntu12.04.2 系统,利用提供的工具和详细的使用步骤,搭建编译环境:另外一种方法是用户安装虚拟机,然后直接加载 “搭建好的U ...

  7. MySQL: ERROR13(HY000):Can't get stat of

    在mysql中load data数据 mysql> load data infile '/home/a.txt' into table table_a;ERROR 13 (HY000): Can ...

  8. iOS中model出来一个控制器的尺寸怎么设置?

    在xib的控制器里添加self.preferredContentSize = CGSizeMake( , ) 就能修改xib在界面上显示的大小- (void)viewDidLoad { [super ...

  9. JS小练习 留言功能

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  10. 无序数组的中位数(set+deque)hdu5249

    KPI Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...