【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 ...
随机推荐
- 用Delphi7开发Web Service程序 转
转:http://rosehacker.blog.51cto.com/2528968/450160 用Delphi7开发Web Service程序,并把服务程序放在IIS Web服务器上提供给 ...
- js 的 提交
<script type="text/javascript"> function sub(){ if(document.form1.xingming.value==&q ...
- Tree2cycle
Problem Description A tree with N nodes and N-1 edges is given. To connect or disconnect one edge, w ...
- octopress的一些总结
1.编辑_config.yml 的description时,不能使用tab键 2.修改主题‘MediumFox’ description 和 文章展示的宽度,修改文件home_landing_row ...
- Sicily1153-马的周游问题:启发式搜索
代码地址: https://github.com/laiy/Datastructure-Algorithm/blob/master/sicily/1153.c 题目如下: 1153. 马的周游问题 C ...
- ndk编译时的通用Android.mk文件
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := live555 MY_SRC_PATH := $(LOCAL_PA ...
- input标签上传图片怎么获取src;
大家都知道input标签可以上传文件 如: <input type="file"/> 就可以上传文件,当然也可以上传图片,上传的图片的src地址如何取到: var re ...
- mysql 建立表里某的个字段根据另一字段进行自增长
在设计一些数据表时,我们经常遇到这样一种情况:需要表中的一个字段根据另一字段进行自增长,比如,在数据表中存储玩家的武器信息时,需要存储玩家的武器对应的bagid,这就是一个根据玩家自己的id(玩家id ...
- 算法----希尔排序(shell sort)
在分析插入排序(插入排序算法实现)的算法性能的过程时知道.当数组规模较小或者存在较多的有序子序列时.插入排序将会在非常短的时间内完毕数组的排序,为此能够设计一个单调序列h[n],将数组分为多个小的序列 ...
- Web性能优化系列
web性能优化之重要,这里并不打算赘述.本系列课程将带领大家认识.熟悉.深刻体会并且懂得如果去为不同的站点做性能优化 同时,本系列将还会穿插浏览器兼容性相关问题的解决方案,因为在我看来,兼容性同样属于 ...