POJ 3237 树链剖分
题目链接: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 树链剖分的更多相关文章
- poj 3237(树链剖分+线段树)
题意:给一棵树,三种操作.将第i条边的权值改为v,将a到b的路径上的边的权值全部取反,求a到b路径上边的权值的最大值. 思路:明显的树链剖分,加上线段树的操作.因为有取反的操作所以每个区间要记录最大值 ...
- POJ 3237 /// 树链剖分 线段树区间修改(*-1)
题目大意: 给定树的N个结点 编号为1到N 给定N-1条边的边权. 三种操作: CHANGE k w:将第 k 条边的权值改成 w. NEGATE x y:将x到y的路径上所有边的权值乘 -1. QU ...
- poj 3237 树链剖分模板(用到线段树lazy操作)
/* 本体在spoj375的基础上加了一些操作,用到线段树的lazy操作模板类型 */ #include<stdio.h> #include<string.h> #includ ...
- POJ 2763 (树链剖分+边修改+边查询)
题目链接:http://poj.org/problem?id=2763 题目大意:某人初始在s点.有q次移动,每次移动沿着树上一条链,每经过一条边有一定花费,这个花费可以任意修改.问每次移动的花费. ...
- POJ 4718 /// 树链剖分+线段树区间合并 求树上两点间的LCIS长度
题目大意: 给定n个点 每个点都有权值 接下来给定树的n条边 第 i 个数 a[i] 表示 i+1到a[i]之间 有一条边 给定q q个询问 每次询问给出 x y 求x到y的最长上升子序列的长度 题解 ...
- POJ 2763 树链剖分 线段树 Housewife Wind
单个边的权值修改以及询问路径上的权值之和. 数据量比较大,用vector存图会超时的. #include <iostream> #include <cstdio> #inclu ...
- HDU 3966 & POJ 3237 & HYSBZ 2243 树链剖分
树链剖分是一个很固定的套路 一般用来解决树上两点之间的路径更改与查询 思想是将一棵树分成不想交的几条链 并且由于dfs的顺序性 给每条链上的点或边标的号必定是连着的 那么每两个点之间的路径都可以拆成几 ...
- POJ 3237:Tree(树链剖分)
http://poj.org/problem?id=3237 题意:树链剖分.操作有三种:改变一条边的边权,将 a 到 b 的每条边的边权都翻转(即 w[i] = -w[i]),询问 a 到 b 的最 ...
- poj 3237 Tree 树链剖分
题目链接:http://poj.org/problem?id=3237 You are given a tree with N nodes. The tree’s nodes are numbered ...
随机推荐
- HDU 1373 XYZZY (spfa的特殊用法)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1317 题目大意:有n个房间,编号1-n,房间之间有单向门连接.某人初始位于1号房间,且具有100点能量 ...
- 026:if标签使用详解
if标签使用详解: if 标签: if 标签相当于 Python 中的 if 语句,有 elif 和 else 相对应,但是所有的标签都需要用标签符号 {% %} 进行包裹. if 标签中可以使 ...
- Linux学习-基于CentOS7的MariaDB数据库的安装
一.实验环境: 系统:CentOS7.6,关闭了防火墙与SELINUX 数据库版本:mariadb-10.2.25(二进制安装与源码安装) 二.安装方法: 1.yum源安装 (1) 配置yum源,官方 ...
- 阿里云吴天议:云原生SDWAN 应用 构建智能化云原生SDWAN生态
2019年11月16日 SDWAN 大会在北京正式召开.阿里云网络资深产品专家吴天议先生继阿里云网络研究员祝顺民先生发表了对云原生SDWAN的进化与展望之后(原文请见https://bit.ly/2K ...
- Java 迭代器删除元素ConcurrentModificationException异常。
Java是不支持容器类在使用迭代器迭代过程中,使用如 list.remove(obj)方法删除元素.否则会抛出ava.util.ConcurrentModificationException异常.应该 ...
- Winner
Winner 南昌邀请赛 暴力模拟 #include<bits/stdc++.h> using namespace std; struct Nod { int i; int a,b,c; ...
- [CSP-S模拟测试97]题解
A.小盆友的游戏 感觉题解解释的很牵强啊……还是打表找规律比较靠谱 对于每个人,它构造了一个期望函数$f(x)$,设它的跟班个数为$cnt[x]$,那么令$f(x)=2^{cnt[x]}-1$(??鬼 ...
- 配置自己的CocoaPods库
序 默认安装的cocoapods确实很好用,可是毕竟自己会写一些库和修改一些第三方库来用.所幸cocoapods确实是一个神器.他可以定义自己的库来用. 如何安装Cocoapods,请参考这篇 从头来 ...
- drawRect
1) 画笔设置 Paint.Style.STROKE 中空模式 paint = new Paint(); //新建一个画笔对象 paint.setAntiAlias(true);//抗锯齿功能 pai ...
- java切分查询数据库表
在实际应用中,我经常用到遇到根据单号查询,单号又是批量如1000个单号,直接1000个in子查询是不行的,子查询是用上限的.如果表中数据达到上百万以上.即使有单号字段有索引查询也是很慢.这时可以用切分 ...