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, ...
随机推荐
- 6、JavaScript进阶篇③——浏览器对象、Dom对象
一.浏览器对象 1. window对象 window对象是BOM的核心,window对象指当前的浏览器窗口. window对象方法: 注意:在JavaScript基础篇中,已讲解了部分属性,windo ...
- 利用DBCC PAGE查看SQL Server中的表和索引数据
16:08 2013-01-06 参考http://doc.chinaunix.net/sqlserver/200810/206034.shtmlDBCC PAGE|IND 参数 DBCC PAGE ...
- Python之路-python环境安装和简单的语法使用
一.环境安装 Win10(安装python3.x): 1.下载安装包 https://www.python.org/downloads/ 2.安装完成后设置环境变量. 桌面-“计算机”-右 ...
- SQLServer数据库的一些全局变量
select APP_NAME ( ) as w --当前会话的应用程序 select @@IDENTITY --返回最后插入的标识值 select USER_NAME() --返回用户数据库用户名 ...
- javaEE开发案例——购物车
一.页面 流程:登录页面(login.jsp)——>购物大厅页面(hall.jsp)——>购物车页面(showMyCart.jsp)——>订单页面(myorder.jsp)——> ...
- Eclipse jar打包
方案一:用Eclipse自带的Export功能 步骤1:准备主清单文件 “MANIFEST.MF”, 由于是打包引用了第三方jar包的Java项目,故需要自定义配置文件MANIFEST.MF,在该项目 ...
- (Protype Pattern)原型模式
定义: 原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的对象 适用性: 当我们系统中有一些类,在使用的时候都有同样需要大量的创建,而这样的创建是复杂的而且是浪费CPU,内存资源的 ...
- Vue.js实例练习
最近学习Vue.js感觉跟不上节奏了,Vue.js用起来很方便. 主要实现功能,能添加书的内容和删除.(用的Bootstrap的样式)demo链接 标题用了自定义组件,代码如下: components ...
- <s:iterator> 对list操作的一种方法
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAA6IAAAH3CAIAAAAuRnW9AAAgAElEQVR4nOzdf4gk1333+wLDDffhPp
- nyist 518 取球游戏
http://acm.nyist.net/JudgeOnline/problem.php?pid=518 取球游戏 时间限制:1000 ms | 内存限制:65535 KB 难度:2 描述 今 ...