题目链接:http://poj.org/problem?id=3237

题意:给定一棵n个结点n-1条边的树。 每条边都是一个边权。 现在有4种操作

1:CHANGE I V:把(输入的)第i条边的边权改为V

2:NEGATE a b:把点a到点b的路径上的边权取反

3:QUERY a b:输出点a到点b的路径上边权最大值。

4:DONE:结束操作。

思路:树链剖分。 涉及的是边权所以把边权转化为点权,做法是将边权赋值到这条边deep大的点上。 剖分后用线段树维护。 1操作对应单点更新 2操作对应区间更新 3操作对应区间查询。

对于2操作。用线段树维护一个结点的最大值和最小值。那么反正相当于把最大值和最小值互换然后分别乘上个(-1)。

#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<stdio.h>
#include<queue>
#include<vector>
#include<stack>
#include<map>
#include<set>
#include<time.h>
#include<cmath>
#include<sstream>
#include<assert.h>
using namespace std;
#define L(x) x<<1
#define R(x) x<<1|1
typedef long long int LL;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;
const int MAXN = + ;
int val[MAXN],head[MAXN], tot, cnt, edgesId[MAXN];
struct Edge{
int to, next;
int value;
}Edges[MAXN * ];
void add(int u, int v, int w){
Edges[tot].to = v;
Edges[tot].value = w;
Edges[tot].next = head[u];
head[u] = tot++;
}
int id[MAXN], son[MAXN], deep[MAXN], size[MAXN], fa[MAXN], reid[MAXN], top[MAXN];
void Init(){
tot = ; cnt = ;
memset(head, -, sizeof(head));
memset(son, -, sizeof(son));
memset(val, , sizeof(val));
}
void DFS1(int u, int p,int dep){
fa[u] = p; size[u] = ; deep[u] = dep;
for (int i = head[u]; i != -; i = Edges[i].next){
if (Edges[i].to != p){
val[Edges[i].to] = Edges[i].value; //deep大的点获得边权
edgesId[(int)ceil(i / 2.0)] = Edges[i].to;
DFS1(Edges[i].to, u,dep+);
size[u] += size[Edges[i].to];
if (son[u] == - || size[Edges[i].to] > size[son[u]]){
son[u] = Edges[i].to;
}
}
}
}
void DFS2(int u, int tp){
id[u] = ++cnt; reid[id[u]] = u; top[u] = tp;
if (son[u] == -){ return; }
DFS2(son[u], tp);
for (int i = head[u]; i != -; i = Edges[i].next){
if (son[u] != Edges[i].to&&Edges[i].to != fa[u]){
DFS2(Edges[i].to, Edges[i].to);
}
}
}
struct Node{
int st, ed;
int lazy, Max, Min;
}Seg[MAXN * ];
void Build(int l, int r, int k){
Seg[k].st = l; Seg[k].ed = r; Seg[k].lazy = ;
if (l == r){
Seg[k].Max = Seg[k].Min = val[reid[l]];
return;
}
int mid = (l + r) / ;
Build(l, mid, L(k)); Build(mid + , r, R(k));
Seg[k].Max = max(Seg[L(k)].Max, Seg[R(k)].Max);
Seg[k].Min = min(Seg[L(k)].Min, Seg[R(k)].Min);
}
void Modify(int k){
swap(Seg[k].Min, Seg[k].Max);
Seg[k].Min *= -;
Seg[k].Max *= -;
}
void pushUp(int k){
Seg[k].Max = max(Seg[L(k)].Max, Seg[R(k)].Max);
Seg[k].Min = min(Seg[L(k)].Min, Seg[R(k)].Min);
}
void pushDown(int k){
if (Seg[k].lazy){
Seg[k].lazy ^= ;
Seg[L(k)].lazy ^= ;
Modify(L(k));
Seg[R(k)].lazy ^= ;
Modify(R(k));
}
}
void CHANGE(int pos, int val, int k){
if (Seg[k].st ==Seg[k].ed){
Seg[k].Max = Seg[k].Min = val;
return;
}
pushDown(k);
if (pos <= Seg[L(k)].ed){
CHANGE(pos, val, L(k));
}
else{
CHANGE(pos, val, R(k));
}
pushUp(k);
}
void NEGATE(int l, int r, int k){
if (Seg[k].st == l&&Seg[k].ed == r){
Seg[k].lazy ^= ;
Modify(k);
return;
}
pushDown(k);
if (r <= Seg[L(k)].ed){
NEGATE(l, r, L(k));
}
else if (l >= Seg[R(k)].st){
NEGATE(l, r, R(k));
}
else{
NEGATE(l, Seg[L(k)].ed, L(k));
NEGATE(Seg[R(k)].st, r, R(k));
}
pushUp(k);
}
void NEGATE(int u, int v){
int f1 = top[u], f2 = top[v];
while (f1 != f2){
if (deep[f1] < deep[f2]){
swap(f1, f2);
swap(u, v);
}
NEGATE(id[f1], id[u], );
u = fa[f1]; f1 = top[u];
}
if (u == v){ return; }
if (deep[u] > deep[v]){
swap(u, v);
}
NEGATE(id[son[u]], id[v], );
}
int Query(int l, int r, int k){
if (Seg[k].st == l&&Seg[k].ed == r){
return Seg[k].Max;
}
int _Max = -inf;
pushDown(k);
if (r <= Seg[L(k)].ed){
_Max = Query(l, r, L(k));
}
else if (l >= Seg[R(k)].st){
_Max = Query(l, r, R(k));
}
else{
_Max = max(Query(l, Seg[L(k)].ed, L(k)), Query(Seg[R(k)].st, r, R(k)));
}
pushUp(k);
return _Max;
}
int Query(int u, int v){
int ans = -inf;
int f1 = top[u], f2 = top[v];
while (f1 != f2){
if (deep[f1] < deep[f2]){
swap(f1, f2);
swap(u, v);
}
ans = max(ans, Query(id[f1], id[u], ));
u = fa[f1]; f1 = top[u];
}
if (u == v){ return ans; }
if (deep[u] > deep[v]){
swap(u, v);
}
ans = max(ans, Query(id[son[u]], id[v], ));
return ans;
}
int main(){
//#ifdef kirito
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
//#endif
// int start = clock();
int n,t;
scanf("%d", &t);
while (t--){
scanf("%d", &n); Init();
for (int i = ; i < n; i++){
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
add(u, v, w); add(v, u, w);
}
DFS1(, , ); DFS2(, ); Build(, n, );
char ope[];
while (scanf("%s",ope)&&ope[]!='D'){
int u,v;
scanf("%d%d", &u,&v);
switch (ope[])
{
case 'Q': printf("%d\n", (u==v?:Query(u, v))); break;
case 'C': CHANGE(id[edgesId[u]], v, ); break;
default: NEGATE(u, v); break;
}
}
}
//#ifdef LOCAL_TIME
// cout << "[Finished in " << clock() - start << " ms]" << endl;
//#endif
return ;
}

POJ 3237 树链剖分的更多相关文章

  1. poj 3237(树链剖分+线段树)

    题意:给一棵树,三种操作.将第i条边的权值改为v,将a到b的路径上的边的权值全部取反,求a到b路径上边的权值的最大值. 思路:明显的树链剖分,加上线段树的操作.因为有取反的操作所以每个区间要记录最大值 ...

  2. POJ 3237 /// 树链剖分 线段树区间修改(*-1)

    题目大意: 给定树的N个结点 编号为1到N 给定N-1条边的边权. 三种操作: CHANGE k w:将第 k 条边的权值改成 w. NEGATE x y:将x到y的路径上所有边的权值乘 -1. QU ...

  3. poj 3237 树链剖分模板(用到线段树lazy操作)

    /* 本体在spoj375的基础上加了一些操作,用到线段树的lazy操作模板类型 */ #include<stdio.h> #include<string.h> #includ ...

  4. POJ 2763 (树链剖分+边修改+边查询)

    题目链接:http://poj.org/problem?id=2763 题目大意:某人初始在s点.有q次移动,每次移动沿着树上一条链,每经过一条边有一定花费,这个花费可以任意修改.问每次移动的花费. ...

  5. POJ 4718 /// 树链剖分+线段树区间合并 求树上两点间的LCIS长度

    题目大意: 给定n个点 每个点都有权值 接下来给定树的n条边 第 i 个数 a[i] 表示 i+1到a[i]之间 有一条边 给定q q个询问 每次询问给出 x y 求x到y的最长上升子序列的长度 题解 ...

  6. POJ 2763 树链剖分 线段树 Housewife Wind

    单个边的权值修改以及询问路径上的权值之和. 数据量比较大,用vector存图会超时的. #include <iostream> #include <cstdio> #inclu ...

  7. HDU 3966 & POJ 3237 & HYSBZ 2243 树链剖分

    树链剖分是一个很固定的套路 一般用来解决树上两点之间的路径更改与查询 思想是将一棵树分成不想交的几条链 并且由于dfs的顺序性 给每条链上的点或边标的号必定是连着的 那么每两个点之间的路径都可以拆成几 ...

  8. POJ 3237:Tree(树链剖分)

    http://poj.org/problem?id=3237 题意:树链剖分.操作有三种:改变一条边的边权,将 a 到 b 的每条边的边权都翻转(即 w[i] = -w[i]),询问 a 到 b 的最 ...

  9. poj 3237 Tree 树链剖分

    题目链接:http://poj.org/problem?id=3237 You are given a tree with N nodes. The tree’s nodes are numbered ...

随机推荐

  1. 共享OrCAD9.2pSpice9.2+multisim下载地址

    http://pan.baidu.com/s/1dDcfiH7ewb9绿色版,解压后即可用!http://pan.baidu.com/s/1kTG43WFMultisim v11绿色版.7zhttp: ...

  2. R reticulate 设置 python 环境

    library("reticulate") use_python("/usr/bin/python", required = T) py_config() 注意 ...

  3. Cobaltstrike系列教程(二)-Listner与Payload生成 heatlevel

    0x000-前文 Cobaltstrike系列教程(一)简介与安装 0x001-Listner(监听器)介绍 ①Cobaltstrike listner简介 可能有一些小白并不理解什么叫做listne ...

  4. 当 Messaging 遇上 Jepsen

    分布式系统面临的挑战 Is it better to be alive and wrong or right and dead? 随着计算机技术的发展,系统架构从集中式演进到分布式.分布式系统相对于单 ...

  5. 使用 Visual Studio 调试器附加到运行的进程

    为什么调试附加进程? Visual Studio 调试器可以附加到在 Visual Studio 外运行的进程. 可以使用此附加功能执行以下操作: 调试并非在 Visual Studio 中创建的应用 ...

  6. php array_merge()函数 语法

    php array_merge()函数 语法 作用:把一个或多个数组合并为一个数组.dd马达选型 语法:array_merge(array1,array2,array3...) 参数: 参数 描述 a ...

  7. 攻防世界 | string

    #encoding=utf-8 #!usr/bin/python from pwn import * io = remote('111.198.29.45',42643) io.recvuntil(& ...

  8. loj#2334 「JOI 2017 Final」JOIOI 王国

    分析 二分答案 判断左上角是否满足 为了覆盖所有范围 我们依次把右下角,左上角,右上角移动到左上角 代码 #include<bits/stdc++.h> using namespace s ...

  9. p5405 [CTS2019]氪金手游

    题目大意 题意狗屁不通 看毛子语都比看这个题面强 分析 我们假设这棵树是一个内向树 那么我们可以轻易的得到dp[x][i]表示x点子树和为i的期望 转移只需枚举当前期望大小和子树期望大小即可 但是由于 ...

  10. 云计算openstack核心组件——keystone身份认证服务

    一.Keystone介绍:       keystone 是OpenStack的组件之一,用于为OpenStack家族中的其它组件成员提供统一的认证服务,包括身份验证.令牌的发放和校验.服务列表.用户 ...