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, ...
随机推荐
- [3D]绘制XYZ小坐标轴
源码: using System; using System.Collections.Generic; using System.Linq; using System.Text; using Slim ...
- fail2ban使用
转子: http://www.2cto.com/Article/201406/310910.html 1.fail2ban简介: fail2ban可以监视你的系统日志,然后匹配日志的错误信息(正则式匹 ...
- 关键字 self
self 总是指向调用方法的对象. self总是代表当前类的对象.当它出现在某个方法体中时,它所代表的对象是不确定的,但它的类型是确定的,它所代表的是当前类的实例对象: 当这个方法被调用时,它所代表的 ...
- CSS 编码规范
转自: https://segmentfault.com/a/1190000005046830 CSS书写格式 1.格式化代码 1.1文件 [建议]:CSS文件使用无BOM的UTF-8编码 1.2缩进 ...
- GTA项目 二, JSON接口开放跨域访问
public class CORSAttribute : ActionFilterAttribute { public string Domains { get; set; } public CORS ...
- redhat linux 安装mysql5.6.27
1.yum安装mysql(root身份) yum install mysql-server mysql-devel mysql -y 如没有配置yum,请参见博客:http://www.cnblogs ...
- C++Primer 第五章
//1.表达式语句的作用:执行表达式并丢弃求值结果 ; value + ; //执行,并丢弃结果 //2.复合语句是指用花括号括起来的语句和声明的序列,复合语句称为块.一个块就是一个作用域.块不以分号 ...
- javascript 一些常用的验证
只能输入数字 onkeyup="this.value=this.value.replace(/[^\d]/g,'')" onafterpaste="th ...
- c++之路进阶——bzoj3343(教主的魔法)
F.A.Qs Home Discuss ProblemSet Status Ranklist Contest ModifyUser gryz2016 Logout 捐赠本站 Notice:由于本OJ ...
- Apache与Nginx虚拟主机设置(多域名和多端口的区别)
为了方便管理虚拟主机,应该尽量少修改主配置文件http.conf或者nginx.conf,大部分修改变更都在虚拟主机片配置文件httpd- vhost.conf或者vhost.conf中完成,这样有利 ...