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. python_模块

    1. 模块的导入 (1) python中import module时,系统通常在哪些路径下面查找模块? 在以下的路径查找模块:sys.path 如果你模块所在的目录,不在sys.path的目录下,可以 ...

  2. Yii中配置单点登录 即多个子站同步登录

    研究Yii的同步登录大概2个多月,几乎查遍了网上所有资料和案例,但都不是很理想,最后摸索出整理出来以下配置方案. 以下配置文件在config.php中,所有需要同步的站点都需要填写.网上一些站点给出的 ...

  3. javascript设计模式学习之九——命令模式

    一.命令模式使用场景及定义 命令模式常见的使用场景是:有时候需要向某些对象发送请求,但是并不知道请求的接受者是谁,也不知道请求的具体操作是什么.此时希望用一种松耦合的方式来设计程序,使得请求的发送者和 ...

  4. UI进阶之--网易彩票手写plist文件,动态创建控制器与tableViewcell

    点击右上角设置按钮 点击按钮后发生的事件:1. 控制器的跳转,进入新的控制器.view, 2. 跳转的时候对将要跳转的目标控制的子控件进行了布局.---通过手写plist文件的方式加载 为按钮注册单击 ...

  5. YII实现Memcache故障转移的配置办法

    YII在默认配置下连接Memcache失败时会报错,要想实现故障转移就要改一下配置和代码 1.首先修改一下YII的 caching/CMemCache.php,我的版本是 1.1.7 找到 $cach ...

  6. 更改Mysql数据库中的数据出现乱码问题

    数据库服务器环境:windows 7 专业版 Mysql版本:5.5.36 出现问题:搭完工程之后,在做保存和插入操作时,涉及的数据在数据库中为变为乱码. 解决方案:         MySQL数据库 ...

  7. Request、Servlet及其子接口

    最近看tomcat源码,这类接口多的有点眩,整理出来看一下.(基于tomcat4) javax.servlet.ServletRequset接口,和org.apache.catalina.Reques ...

  8. JQuery Delay Hover效果

    CSS代码 .tbui_aside_float_bar { position: fixed; left: 50%; bottom: 120px; margin-left: 608px; border- ...

  9. PPTP部署文档

    PPTP部署文档 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.       欢迎加入:高级运维工程师之路 598432640 前言:这款VPN部署起来特别简单,想对OPENVON配 ...

  10. 强连通(hdu4635)最多增加几条单向边后满足最终的图形不是强连通

    Strongly connected Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Other ...