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. VSTO Project 客户端自动发送邮件

    利用office vsto功能,抓取我们选择的任务,根据配置节,邮件发送内容,最终根据任务名称,任务开始结束时间,任务资源名称,发送邮件给任务资源. 这是我的VSTO界面. 配置我们发送邮件的服务器地 ...

  2. SpringBoot非官方教程 | 第十八篇: 定时任务(Scheduling Tasks)

    转载请标明出处: 原文首发于:https://www.fangzhipeng.com/springboot/2017/07/11/springboot18-scheduling/ 本文出自方志朋的博客 ...

  3. eclipse的中文插件链接及使用方法

    链接:http://www.eclipse.org/babel/downloads.php 帮助-->安装-->打开链接使用链接里面的语言包下载地址-->下载安装-->完成

  4. MySQL提升课程 全面讲解MySQL架构设计-索引

    索引是什么? 索引是帮助MySQL高效获取数据的数据结构. 索引能干什么? 提高数据查询的效率. 索引:排好序的快速查找数据结构!索引会影响where后面的查找,和order by 后面的排序. 一. ...

  5. JSP的小心得

    问题:Web容器(例如Tomcat)是怎么来执行jsp文件的? 首先它会将放在webapps目录下的jsp文件(这里以hello.jsp为例)翻译成hello_jsp.java文件并编译为hello_ ...

  6. Javascript中的this对象

    对于this的使用,我们最常遇到的主要有,在全局函数中,在对象方法中,call和apply时,闭包中,箭头函数中以及class中: 我们知道this对象是在运行时基于函数的执行环境绑定的,在调用函数之 ...

  7. IOException parsing XML document from ServletContext resource [/WEB-INF/applicationContext.xml]; nested exception is java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/app

    web.xml初始化spring容器出错 org.springframework.beans.factory.BeanDefinitionStoreException: IOException par ...

  8. Linux下通过uptime判断负载情况

    [root@localhost ~]# uptime 18:34:12 up 5:30, 1 user, load average: 0.00, 0.01, 0.05 load average后面的三 ...

  9. 新知识 HtMl 5

    快要毕业了,即将走向实习岗位,但是这日子过的太无聊了,昨天逃课回宿舍打开电脑想看电影但是没什么好看的,于是上床睡觉了,越躺越无聊,然后爬了起来到学习图书馆找了本HTML5的课本,学习了起来(我感觉ht ...

  10. Laravel-初步使用

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