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

We will ask you to perfrom some instructions of the following form:

  • CHANGE i ti : change the cost of the i-th edge to ti
    or
  • QUERY a b : ask for the maximum edge cost on the path from node a to node b

Input

The first line of input contains an integer t, the number of test cases (t <= 20). t test cases follow.

For each test case:

  • In the first line there is an integer N (N <= 10000),
  • In the next N-1 lines, the i-th line describes the i-th edge: a line with three integers a b c denotes an edge between ab of cost c (c <= 1000000),
  • The next lines contain instructions "CHANGE i ti" or "QUERY a b",
  • The end of each test case is signified by the string "DONE".

There is one blank line between successive tests.

Output

For each "QUERY" operation, write one integer representing its result.

Example

Input:
1 3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE Output:
1
3

推荐论文:《树链剖分》:http://wenku.baidu.com/view/a088de01eff9aef8941e06c3.html

《QTREE解法的一些研究》:随便百度一下就有

思路:树链剖分,上面都讲得比较清楚了我就不讲了。对着树链剖分的伪代码写的,那个伪代码有一个错误(应该是错误吧……),询问那里应该是x = father[top[x]]。还有,在这题用线段树,点的权值记录与父节点的边的权值,那么最后的询问是要query(tid[x]+1, tid[y])

代码(3840MS):

 #include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std; const int MAXN = ;
const int MAXE = * MAXN;
const int INF = 0x7fffffff; int head[MAXN], cost[MAXN], id[MAXN];
int weight[MAXE], to[MAXE], next[MAXE];
int n, ecnt; inline void init() {
memset(head, , sizeof(head));
ecnt = ;
} inline void add_edge(int u, int v, int c) {
to[ecnt] = v; weight[ecnt] = c; next[ecnt] = head[u]; head[u] = ecnt++;
to[ecnt] = u; weight[ecnt] = c; next[ecnt] = head[v]; head[v] = ecnt++;
} int maxt[MAXN * ]; void modify(int x, int left, int right, int a, int b, int val) {
if(a <= left && right <= b) maxt[x] = val;
else {
int ll = x << , rr = ll ^ ;
int mid = (left + right) >> ;
if(a <= mid) modify(ll, left, mid, a, b, val);
if(mid < b) modify(rr, mid + , right, a, b, val);
maxt[x] = max(maxt[ll], maxt[rr]);
}
} int query(int x, int left, int right, int a, int b) {
if(a <= left && right <= b) return maxt[x];
else {
int ll = x << , rr = ll ^ ;
int mid = (left + right) >> , ret = ;
if(a <= mid) ret = max(ret, query(ll, left, mid, a, b));
if(mid < b) ret = max(ret, query(rr, mid + , right, a, b));
return ret;
}
} int size[MAXN], fa[MAXN], dep[MAXN], son[MAXN];
int tid[MAXN], top[MAXN], dfs_clock; void dfs_size(int u, int f, int depth) {
fa[u] = f; dep[u] = depth;
size[u] = ; son[u] = ;
int maxsize = ;
for(int p = head[u]; p; p = next[p]) {
int &v = to[p];
if(v == f) continue;
cost[v] = weight[p];
dfs_size(v, u, depth + );
size[u] += size[v];
if(size[v] > maxsize) {
maxsize = size[v];
son[u] = v;
}
}
} void dfs_heavy_edge(int u, int ancestor) {
tid[u] = ++dfs_clock; top[u] = ancestor;
modify(, , n, tid[u], tid[u], cost[u]);
if(son[u]) dfs_heavy_edge(son[u], ancestor);
for(int p = head[u]; p; p = next[p]) {
int &v = to[p];
if(v == fa[u] || v == son[u]) continue;
dfs_heavy_edge(v, v);
}
} int query(int x, int y) {
int ret = ;
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
ret = max(ret, query(, , n, tid[top[x]], tid[x]));
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x, y);
ret = max(ret, query(, , n, tid[x] + , tid[y]));
return ret;
} void change(int x, int y) {
int u = to[x], v = to[x ^ ];
if(fa[u] == v) swap(u, v);
modify(, , n, tid[v], tid[v], y);
} char str[]; int main() {
int T; scanf("%d", &T);
for(int t = ; t <= T; ++t) {
scanf("%d", &n);
init();
for(int i = ; i < n; ++i) {
int u, v, c;
scanf("%d%d%d", &u, &v, &c);
id[i] = ecnt;
add_edge(u, v, c);
}
memset(maxt, , sizeof(maxt));
dfs_size(, , ); cost[] = -INF;
dfs_clock = ;
dfs_heavy_edge(, );
while(scanf("%s", str) && *str != 'D') {
int x, y;
scanf("%d%d", &x, &y);
if(*str == 'C') change(id[x], y);
else printf("%d\n", query(x, y));
}
}
}

代码(3400MS)(加了个IO优化……):

 #include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cctype>
using namespace std; const int MAXN = ;
const int MAXE = * MAXN;
const int INF = 0x7fffffff; int head[MAXN], cost[MAXN], id[MAXN];
int weight[MAXE], to[MAXE], next[MAXE];
int n, ecnt; inline void init() {
memset(head, , sizeof(head));
ecnt = ;
} inline void add_edge(int u, int v, int c) {
to[ecnt] = v; weight[ecnt] = c; next[ecnt] = head[u]; head[u] = ecnt++;
to[ecnt] = u; weight[ecnt] = c; next[ecnt] = head[v]; head[v] = ecnt++;
} int maxt[MAXN * ]; void modify(int x, int left, int right, int a, int b, int val) {
if(a <= left && right <= b) maxt[x] = val;
else {
int ll = x << , rr = ll ^ ;
int mid = (left + right) >> ;
if(a <= mid) modify(ll, left, mid, a, b, val);
if(mid < b) modify(rr, mid + , right, a, b, val);
maxt[x] = max(maxt[ll], maxt[rr]);
}
} int query(int x, int left, int right, int a, int b) {
if(a <= left && right <= b) return maxt[x];
else {
int ll = x << , rr = ll ^ ;
int mid = (left + right) >> , ret = ;
if(a <= mid) ret = max(ret, query(ll, left, mid, a, b));
if(mid < b) ret = max(ret, query(rr, mid + , right, a, b));
return ret;
}
} int size[MAXN], fa[MAXN], dep[MAXN], son[MAXN];
int tid[MAXN], top[MAXN], dfs_clock; void dfs_size(int u, int f, int depth) {
fa[u] = f; dep[u] = depth;
size[u] = ; son[u] = ;
int maxsize = ;
for(int p = head[u]; p; p = next[p]) {
int &v = to[p];
if(v == f) continue;
cost[v] = weight[p];
dfs_size(v, u, depth + );
size[u] += size[v];
if(size[v] > maxsize) {
maxsize = size[v];
son[u] = v;
}
}
} void dfs_heavy_edge(int u, int ancestor) {
tid[u] = ++dfs_clock; top[u] = ancestor;
modify(, , n, tid[u], tid[u], cost[u]);
if(son[u]) dfs_heavy_edge(son[u], ancestor);
for(int p = head[u]; p; p = next[p]) {
int &v = to[p];
if(v == fa[u] || v == son[u]) continue;
dfs_heavy_edge(v, v);
}
} int query(int x, int y) {
int ret = ;
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
ret = max(ret, query(, , n, tid[top[x]], tid[x]));
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x, y);
ret = max(ret, query(, , n, tid[x] + , tid[y]));
return ret;
} void change(int x, int y) {
int u = to[x], v = to[x ^ ];
if(fa[u] == v) swap(u, v);
modify(, , n, tid[v], tid[v], y);
} char str[]; inline int readint() {
char c = getchar();
while(!isdigit(c)) c = getchar();
int ret = ;
while(isdigit(c)) ret = ret * + c - '', c = getchar();
return ret;
} int main() {
int T = readint();
for(int t = ; t <= T; ++t) {
n = readint();
init();
for(int i = ; i < n; ++i) {
int u = readint(), v = readint(), c = readint();
id[i] = ecnt;
add_edge(u, v, c);
}
memset(maxt, , sizeof(maxt));
dfs_size(, , ); cost[] = -INF;
dfs_clock = ;
dfs_heavy_edge(, );
while(scanf("%s", str) && *str != 'D') {
int x = readint(), y = readint();
if(*str == 'C') change(id[x], y);
else printf("%d\n", query(x, y));
}
}
}

SPOJ 375 Query on a tree(树链剖分)(QTREE)的更多相关文章

  1. spoj 375 Query on a tree (树链剖分)

    Query on a tree You are given a tree (an acyclic undirected connected graph) with N nodes, and edges ...

  2. SPOJ 375 Query on a tree 树链剖分模板

    第一次写树剖~ #include<iostream> #include<cstring> #include<cstdio> #define L(u) u<&l ...

  3. spoj 375 QTREE - Query on a tree 树链剖分

    题目链接 给一棵树, 每条边有权值, 两种操作, 一种是将一条边的权值改变, 一种是询问u到v路径上最大的边的权值. 树链剖分模板. #include <iostream> #includ ...

  4. SPOJ QTREE Query on a tree 树链剖分+线段树

    题目链接:http://www.spoj.com/problems/QTREE/en/ QTREE - Query on a tree #tree You are given a tree (an a ...

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

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

  6. spoj QTREE - Query on a tree(树链剖分+线段树单点更新,区间查询)

    传送门:Problem QTREE https://www.cnblogs.com/violet-acmer/p/9711441.html 题解: 树链剖分的模板题,看代码比看文字解析理解来的快~~~ ...

  7. SPOJ QTREE Query on a tree ——树链剖分 线段树

    [题目分析] 垃圾vjudge又挂了. 树链剖分裸题. 垃圾spoj,交了好几次,基本没改动却过了. [代码](自带常数,是别人的2倍左右) #include <cstdio> #incl ...

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

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

  9. Bzoj 2588 Spoj 10628. Count on a tree(树链剖分LCA+主席树)

    2588: Spoj 10628. Count on a tree Time Limit: 12 Sec Memory Limit: 128 MB Description 给定一棵N个节点的树,每个点 ...

  10. SPOJ QTREE Query on a tree --树链剖分

    题意:给一棵树,每次更新某条边或者查询u->v路径上的边权最大值. 解法:做过上一题,这题就没太大问题了,以终点的标号作为边的标号,因为dfs只能给点分配位置,而一棵树每条树边的终点只有一个. ...

随机推荐

  1. JavaScript:改变 HTML 样式

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  2. Spring知识点总结(一)

       1. 框架概述        所谓的框架其实就是程序的架子,在这个程序的架子中,搭建起程序的基本的骨架,针对程序的通用问题给出了便捷的解决方案,可以使开发人员 基于框架快速开发具体的应用程序.  ...

  3. Java的内存--存储(1)

    有次去面试,面试官突然问我这个问题,当时我只知道怎么写最优化,但是具体不知道为什么那样写,身价立马下降哦 1. 以下开发习惯,你怎么看? for(int i=0;i<2;i++){ Person ...

  4. Linux基础 ppt pptx

    引言 以前写过一个讲 Linux 基础的ppt,琢磨着把它分享出来,有需要的请自取. 部分截图如下 下载地址 下载地址1

  5. python核心编程2 第十三章 练习

    13-3.对类进行定制.写一个类,用来将浮点型值转换为金额. class MoneyFmt(object): def __init__(self, value=0.0, flag='-'): self ...

  6. jdbc最基础的mysql操作

    1.基本的数据库操作 这里连接数据库可以做成一个单独的utils类,我这里因为程序少就没有封装. 虽然现在jdbc被其他框架取代了,但这是框架的基础 如下:第一个是插入数据操作 package Dat ...

  7. Laravel-初步使用

    一.Laravel环境搭建 1.window环境下环境搭建请参考以下链接: 开发环境搭建 - Windows | <Laravel 开发环境部署> | PHP / Laravel 社区文档 ...

  8. Hadoop(14)-MapReduce框架原理-切片机制

    1.FileInputFormat切片机制 切片机制 比如一个文件夹下有5个小文件,切片时会切5个片,而不是一个片 案例分析 2.FileInputFormat切片大小的参数配置 源码中计算切片大小的 ...

  9. Hadoop(8)-HDFS的读写数据流程以及机架感知

    1. HDFS的写数据流程 1.客户端通过fs模块向NameNode申请文件上传,NameNode检查请求是否合法,如用户权限,目标文件是否已存在,父目录是否存在等等 2.NameNode返回是否可以 ...

  10. keil5 mdk调用外部编辑器notepad++、sublime3、VSCode总结

    1.打开keil主界面,点击菜单栏Tools菜单,选择如下图所示的选项. 2.点击如下图所示的菜单上红笔标注的地方,给这个工具命名,如notepad++.sublime3.vscode等,如下图, 并 ...