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的更多相关文章

  1. POJ3237 (树链剖分+线段树)

    Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...

  2. poj3237树链剖分边权+区间取负

    树链剖分+线段树lazy-tag在树链上操作时千万不要写错.. /* 树链剖分+线段树区间变负 */ #include<iostream> #include<cstring> ...

  3. poj3237 树链剖分 暴力

    NEGATE a,b 将a b间的线段取反,这题应该用线段树+成段更新.我成段更新写的挫了,试了暴力修改过了(数据水). 也是简单的题目.不过要注意点和边的区别. #include<queue& ...

  4. 【POJ3237】Tree(树链剖分)

    题意:在一棵N个节点,有边权的树上维护以下操作: 1:单边修改,将第X条边的边权修改成Y 2:区间取反,将点X与Y在树上路径中的所有边边权取反 3:区间询问最大值,询问X到Y树上路径中边权最大值 n& ...

  5. 【POJ3237】Tree(树链剖分+线段树)

    Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...

  6. POJ3237 Tree 树链剖分 线段树

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ3237 题意概括 Description 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1 ...

  7. [POJ3237]Tree解题报告|树链剖分|边剖

    关于边剖 之前做的大多是点剖,其实转换到边剖非常简单. 我的做法是每个点的点权记录其到父亲节点的边的边权. 只要solve的时候不要把最上面的点记录在内就可以了. Tree Description Y ...

  8. POJ3237 Tree 树链剖分 边权

    POJ3237 Tree 树链剖分 边权 传送门:http://poj.org/problem?id=3237 题意: n个点的,n-1条边 修改单边边权 将a->b的边权取反 查询a-> ...

  9. Cogs 1583. [POJ3237]树的维护 LCT,树链剖分

    题目:http://cojs.tk/cogs/problem/problem.php?pid=1583 1583. [POJ3237]树的维护 ★★★☆   输入文件:maintaintree.in  ...

随机推荐

  1. linux 内核驱动加载过程中 向文件系统中的文件进行读写操作

    utils.h 文件: #ifndef __UTILS_H__ #define __UTILS_H__ void a2f(const char *s, ...); #endif utils.c 文件: ...

  2. The breakpoint will not currently be hit. vs2005断点不被命中

    用会了vs2005但是发现坑爹的连断点都不会命中,原来是默认设置的问题.要使断点命中: 1. 首先确保程序是在DEBUG模式下运行: 2. 确认正确的项目设置:链接器->调试->生成调试信 ...

  3. 浅谈数据结构-Boyer-Moore算法

    上文讲解了KMP算法,这种算法在字符串匹配中应用比较少,在各种文本编辑器中的查找功能大多采用Boyer-Moore算法.1977年,德克萨斯大学的Robert S. Boyer教授和J Strothe ...

  4. Windows Live Writer的Markdown插件

    我新写了一个Windows Live Writer的Markdown插件,代码放在了github上. 介绍 这个项目是一个Windows Live Writer的Markdown插件.有了这个插件,你 ...

  5. ng-if与ng-show、ng-hide指令的区别和注意事项

    http://blog.csdn.net/aitangyong/article/details/44701769

  6. Windows 服务卸载之后 重新安装提示 “指定的服务已标记为删除”

    背景:        将一个项目做成一个windows服务,在调试的时候,需要卸载.安装该服务,但提示下面的错误:“指定的服务已标记为删除”,进入服务管理界面,启动自己注册的服务,无法手动更改成启用模 ...

  7. Bootstrap-基于bootstrap的后台二级垂直菜单

    最近做一个后台的管理项目,用到了Twitter推出的bootstrap前端开发工具包,是一个基于css3/html5的框架.花周末时间,写了一个非常简单后台的菜单.首先,看一下菜单的结构: 预览地址  ...

  8. 在C#中使用InputBox

    以前用VB编程常用InputBox,现在学了C#,竟然找不到它了--后来到网上查到了,现在贡献给大家:1.首先要添加引用Microsoft.VisualBasic2.命名空间 Using Micros ...

  9. Apache让一台虚拟主机接受多域名解析(转)

    之前写了一篇文章关于linux下apache虚拟主机配置,配置那是相当简单: <VirtualHost *:80> ServerAdmin admin@example.com Docume ...

  10. ExtJs4学习(四):Extjs 中id与itemId的差别

       为了方便表示或是指定一个组件的名称,我们一般会使用id或者itemId进行标识命名. (推荐尽量使用itemId.这样能够降低页面唯一标识而产生的冲突) id:   id是作为整个页面的Comp ...