【POJ3237】【树链剖分】Tree
Description
You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbered 1 through N − 1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. The instructions can be one of the following forms:
CHANGE i v |
Change the weight of the ith edge to v |
NEGATE a b |
Negate the weight of every edge on the path from a to b |
QUERY a b |
Find the maximum weight of edges on the path from a to b |
Input
The input contains multiple test cases. The first line of input contains an integer t (t ≤ 20), the number of test cases. Then follow the test cases.
Each test case is preceded by an empty line. The first nonempty line of its contains N (N ≤ 10,000). The next N − 1 lines each contains three integers a, b and c, describing an edge connecting nodes a and b with weight c. The edges are numbered in the order they appear in the input. Below them are the instructions, each sticking to the specification above. A lines with the word “DONE” ends the test case.
Output
For each “QUERY” instruction, output the result on a separate line.
Sample Input
1 3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE
Sample Output
1
3
Source
/*
宋代苏轼
《南乡子·重九涵辉楼呈徐君猷》
霜降水痕收。浅碧鳞鳞露远洲。酒力渐消风力软,飕飕。破帽多情却恋头。
佳节若为酬。但把清尊断送秋。万事到头都是梦,休休。明日黄花蝶也愁。
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <utility>
#include <iomanip>
#include <string>
#include <cmath>
#include <queue>
#include <assert.h>
#include <map>
#include <ctime>
#include <cstdlib>
#include <stack>
#define LOCAL
const int INF = 0x3f3f3f3f;
const int maxn= + ;
const int maxnode = ;
const int maxm= * + ;
using namespace std;
struct Node{//权值线段树
int l, r;
int Max, Min;
bool neg;//取反标记
}tree[maxn * ];
struct Edge{
int u, v, w;
}edges[maxn];//输入的边 int n, fa[maxn], size[maxn];
int son[maxn], dep[maxn], top[maxn];
int pos[maxn], Time;
int M, head[maxn], next[maxm], to[maxm], w[maxm]; //第一次dfs
void dfs_1(int u){
size[u] = ;
son[u] = ;
for (int i = head[u]; i != -; i = next[i]){
int v = to[i];
if (v == fa[u]) continue;
dep[v] = dep[u] + ;
fa[v] = u;
dfs_1(v);
size[u] += size[v];
if (size[v] > size[son[u]]) son[u] = v;
}
return;
}
void dfs_2(int u, int top_node){
top[u] = top_node;
pos[u] = ++Time;//给他和他的父亲的边在线段树中的位置
//重边
if (son[u]) dfs_2(son[u], top_node);
//轻边
for (int i = head[u]; i != -; i = next[i]){
int v = to[i];
if (v == fa[u] || v == son[u]) continue;
dfs_2(v, v);
}
}
//建树
void build(int x, int l, int r){
tree[x].l = l;tree[x].r = r;
tree[x].Max = -INF;
tree[x].Min = INF;
tree[x].neg = ;
if (l == r) return; int mid = (l + r) >> ;
build(x << , l, mid);
build((x << ) | , mid + , r);
}
void update(int x){
tree[x].Max = max(tree[x << ].Max, tree[(x << ) | ].Max);
tree[x].Min = min(tree[x << ].Min, tree[(x << ) | ].Min);
return;
}
//标记下传
void pushdown(int x){
if (tree[x].l == tree[x].r) return; if (tree[x].neg){
int l = (x << ), r = l | ;
tree[l].neg ^= ;
tree[l].Min *= -;
tree[l].Max *= -;
swap(tree[l].Min, tree[l].Max); tree[r].neg ^= ;
tree[r].Min *= -;
tree[r].Max *= -;
swap(tree[r].Min, tree[r].Max); tree[x].neg = ;
}
}
//在线段树中修改l,r为val
void change2(int x, int l, int r, int val){
pushdown(x);
if (tree[x].l == l && tree[x].r == r){
if (val == INF){//取反操作,注意已经pushdown过了
tree[x].neg = ;
tree[x].Min *= -;
tree[x].Max *= -;
swap(tree[x].Min, tree[x].Max);
} else tree[x].Min = tree[x].Max = val;//更新val
return;
} int mid = (tree[x].l + tree[x].r) >> ;
if (r <= mid) change2(x << , l, r, val);
else if (l > mid) change2((x << ) | , l, r, val);
else{
change2(x << , l, mid, val);
change2((x << ) | , mid + , r, val);
}
update(x);
}
int query2(int x, int l, int r){
pushdown(x);
if (tree[x].l == l && tree[x].r == r) return tree[x].Max; int mid = (tree[x].l + tree[x].r) >> ;
if (r <= mid) return query2(x << , l, r);
else if (l > mid) return query2((x << ) | , l, r);
else return max(query2((x << ), l, mid), query2((x << ) | , mid + , r));
}
//树链剖分部分
void change(int x, int y, int v){
while (top[x] != top[y]){
//总是矮的往上爬..
//保证dep[top[x]] >= dep[top[y]]
if (dep[top[x]] < dep[top[y]]) swap(x, y); change2(, pos[top[x]], pos[x], v);
x = fa[top[x]];
} if (x == y) return;
if (dep[x] > dep[y]) swap(x, y);
change2(, pos[son[x]], pos[y], v);
}
int query(int x, int y){
int Ans = -INF;
while (top[x] != top[y]){
if (dep[top[x]] < dep[top[y]]) swap(x, y); Ans = max(Ans, query2(, pos[top[x]], pos[x]));
x = fa[top[x]];
}
if (x == y) return Ans;
if (dep[x] > dep[y]) swap(x, y);
Ans = max(Ans, query2(, pos[son[x]], pos[y]));
return Ans == -INF ? : Ans;
}
void work(){
while(){
char str[];
scanf("%s", str);
if(str[] == 'C'){
int x, v;
scanf("%d%d", &x, &v);
change2(, pos[edges[x].v], pos[edges[x].v], v);
}else if(str[] == 'N'){
int l, r;
scanf("%d%d", &l, &r);
change(l, r, INF);
}else if(str[] == 'Q'){//询问两点之间最大值
int l, r;
scanf("%d%d", &l, &r);
printf("%d\n", query(l, r));
}else break;
}
}
//加边
void addEdge(int u, int v, int c){
to[M] = v;
w[M] = c;
next[M] = head[u];
head[u] = M++;
}
void init(){
memset(head, -, sizeof(head));//邻接表初始化
memset(dep, , sizeof(dep));
M = Time = ;//总边数和时间
fa[] = size[] = ;
//加边
scanf("%d", &n);
for (int i = ; i < n; i++){
scanf("%d%d%d", &edges[i].u, &edges[i].v, &edges[i].w);
addEdge(edges[i].u, edges[i].v, edges[i].w);
addEdge(edges[i].v, edges[i].u, edges[i].w);
}
dfs_1();
dfs_2(, );
build(, , Time);
for (int i = ; i < n; i++){
int x = edges[i].u, y = edges[i].v;
//判断父亲
if (dep[x] > dep[y]) swap(edges[i].u, edges[i].v);
//u一定是父亲
change2(, pos[edges[i].v], pos[edges[i].v], edges[i].w);
}
} int main(){
int T; scanf("%d", &T);
while (T--){
init();
work();
}
//printf("%d\n", INF);
return ;
}
【POJ3237】【树链剖分】Tree的更多相关文章
- POJ3237 (树链剖分+线段树)
Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...
- poj3237树链剖分边权+区间取负
树链剖分+线段树lazy-tag在树链上操作时千万不要写错.. /* 树链剖分+线段树区间变负 */ #include<iostream> #include<cstring> ...
- poj3237 树链剖分 暴力
NEGATE a,b 将a b间的线段取反,这题应该用线段树+成段更新.我成段更新写的挫了,试了暴力修改过了(数据水). 也是简单的题目.不过要注意点和边的区别. #include<queue& ...
- 【POJ3237】Tree(树链剖分)
题意:在一棵N个节点,有边权的树上维护以下操作: 1:单边修改,将第X条边的边权修改成Y 2:区间取反,将点X与Y在树上路径中的所有边边权取反 3:区间询问最大值,询问X到Y树上路径中边权最大值 n& ...
- 【POJ3237】Tree(树链剖分+线段树)
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
- POJ3237 Tree 树链剖分 线段树
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ3237 题意概括 Description 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1 ...
- [POJ3237]Tree解题报告|树链剖分|边剖
关于边剖 之前做的大多是点剖,其实转换到边剖非常简单. 我的做法是每个点的点权记录其到父亲节点的边的边权. 只要solve的时候不要把最上面的点记录在内就可以了. Tree Description Y ...
- POJ3237 Tree 树链剖分 边权
POJ3237 Tree 树链剖分 边权 传送门:http://poj.org/problem?id=3237 题意: n个点的,n-1条边 修改单边边权 将a->b的边权取反 查询a-> ...
- Cogs 1583. [POJ3237]树的维护 LCT,树链剖分
题目:http://cojs.tk/cogs/problem/problem.php?pid=1583 1583. [POJ3237]树的维护 ★★★☆ 输入文件:maintaintree.in ...
随机推荐
- linux 内核驱动加载过程中 向文件系统中的文件进行读写操作
utils.h 文件: #ifndef __UTILS_H__ #define __UTILS_H__ void a2f(const char *s, ...); #endif utils.c 文件: ...
- The breakpoint will not currently be hit. vs2005断点不被命中
用会了vs2005但是发现坑爹的连断点都不会命中,原来是默认设置的问题.要使断点命中: 1. 首先确保程序是在DEBUG模式下运行: 2. 确认正确的项目设置:链接器->调试->生成调试信 ...
- 浅谈数据结构-Boyer-Moore算法
上文讲解了KMP算法,这种算法在字符串匹配中应用比较少,在各种文本编辑器中的查找功能大多采用Boyer-Moore算法.1977年,德克萨斯大学的Robert S. Boyer教授和J Strothe ...
- Windows Live Writer的Markdown插件
我新写了一个Windows Live Writer的Markdown插件,代码放在了github上. 介绍 这个项目是一个Windows Live Writer的Markdown插件.有了这个插件,你 ...
- ng-if与ng-show、ng-hide指令的区别和注意事项
http://blog.csdn.net/aitangyong/article/details/44701769
- Windows 服务卸载之后 重新安装提示 “指定的服务已标记为删除”
背景: 将一个项目做成一个windows服务,在调试的时候,需要卸载.安装该服务,但提示下面的错误:“指定的服务已标记为删除”,进入服务管理界面,启动自己注册的服务,无法手动更改成启用模 ...
- Bootstrap-基于bootstrap的后台二级垂直菜单
最近做一个后台的管理项目,用到了Twitter推出的bootstrap前端开发工具包,是一个基于css3/html5的框架.花周末时间,写了一个非常简单后台的菜单.首先,看一下菜单的结构: 预览地址 ...
- 在C#中使用InputBox
以前用VB编程常用InputBox,现在学了C#,竟然找不到它了--后来到网上查到了,现在贡献给大家:1.首先要添加引用Microsoft.VisualBasic2.命名空间 Using Micros ...
- Apache让一台虚拟主机接受多域名解析(转)
之前写了一篇文章关于linux下apache虚拟主机配置,配置那是相当简单: <VirtualHost *:80> ServerAdmin admin@example.com Docume ...
- ExtJs4学习(四):Extjs 中id与itemId的差别
为了方便表示或是指定一个组件的名称,我们一般会使用id或者itemId进行标识命名. (推荐尽量使用itemId.这样能够降低页面唯一标识而产生的冲突) id: id是作为整个页面的Comp ...