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. 自动化测试selenium教程

    什么是自动化测试: 自动帮我们测试一个系统里面的主要功能,一个app.电脑网站.网页,每个系里面许多的功能,好比一个淘宝页面,里面N多功能,登录.注册,推荐,商品详情.评论等等:软件生命周期:需求调研 ...

  2. 【赛时总结】NOIP2018-三校联考1024

    ◇NOIP三校联考-1024◇ 发现以前的博客写得似乎都很水……基本上都没什么阅读量QwQ 决定改过自新╰( ̄ω ̄o) 就从这篇博客开始吧~ 现场考得无地自容,看到题解才发现一些东西……(我第三题还没 ...

  3. 【学时总结】◆学时·IX◆ 整体二分

    ◆学时·IX◆ 整体二分 至于我怎么了解到这个算法的……只是因为发现一道题,明显的二分查找,但是时间会爆炸,被逼无奈搜题解……然后就发现了一些东西QwQ ◇ 算法概述 整体二分大概是把BFS与二分查找 ...

  4. Git基本使用及工具

    好久没用git管理代码了,最近忙着要实习,一直在看面试题,后天入职了,就提前再复习一下git吧. git比较方便的两个网站,如果你想逼格高就用GitHub(https://github.com/),如 ...

  5. vue 路由对象(常用的)

    路由对象 在使用了 vue-router 的应用中,路由对象会被注入每个组件中,赋值为 this.$route ,并且当路由切换时,路由对象会被更新. 路由对象暴露了以下属性: $route.path ...

  6. Python学习手册之控制结构(二)

    在上一篇文章中,我们介绍了Python的一些控制结构,现在我们继续介绍剩下的 Python 控制结构.查看上一篇文章请点击:https://www.cnblogs.com/dustman/p/9972 ...

  7. PHP代码统计文件大小(自动确定单位)

    php中有一个系统自带的计算文件大小的函数,就是filesize(),但是这个函数是以字节为单位的,但是在一些情况下,我们需要很直观的了解一个文件大小,就不仅仅需要字节B这个单位了,还需要KB,MB, ...

  8. 按平均成绩从高到低显示所有学生的“数据库”、“企业管理”、“英语”三门的课程成绩,按如下形式显示: 学生ID,,数据库,企业管理,英语,有效课程数,有效平均分

    SELECT S# as 学生ID ,(SELECT score FROM SC WHERE SC.S#=t.S# AND C#='004') AS 数据库 ,(SELECT score FROM S ...

  9. python2.7入门---SMTP发送邮件

        SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式.python的smtplib提 ...

  10. Microsoft Security Essentials 和 Windows Defender 离线升级包下载地址

    自从微软提供了免费的杀毒软件之后我就卸载掉了其他的杀毒软件.但是最近遇到了个小问题,我这里有一批电脑不能联网,杀毒软件的升级成了问题.在网上搜索了一番,终于找到了官方的离线升级包下载地址.放在这里备用 ...