树链剖分后线段树维护区间最大最小值与和. 支持单点修改与区间取反.

直接写个区间取反标记就行了.线段树板题.(200行6000B+ 1A警告)

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
inline void read(int &num) {
char ch; int flg=1; while(!isdigit(ch=getchar()))if(ch=='-')flg=-flg;
for(num=0; isdigit(ch); num=num*10+ch-'0',ch=getchar()); num*=flg;
}
const int MAXN = 100005;
const int INF = 1e9; int n, m, cnt, tmr, bel[MAXN], a[MAXN], w[MAXN], fir[MAXN], fa[MAXN], dfn[MAXN], top[MAXN], sz[MAXN], son[MAXN], dep[MAXN];
struct edge { int to, nxt, w, id; }e[MAXN<<1];
inline void Add(int u, int v, int wt, int i) {
e[cnt] = (edge){ v, fir[u], wt, i }, fir[u] = cnt++;
e[cnt] = (edge){ u, fir[v], wt, i }, fir[v] = cnt++;
}
void dfs(int x) {
dep[x] = dep[fa[x]] + (sz[x]=1);
for(int v, i = fir[x]; ~i; i = e[i].nxt)
if((v=e[i].to) != fa[x]) {
fa[v] = x, a[v] = e[i].w;
bel[e[i].id] = v;
dfs(v), sz[x] += sz[v];
if(sz[v] > sz[son[x]]) son[x] = v;
}
}
void dfs2(int x, int tp) {
top[x] = tp; w[dfn[x] = ++tmr] = a[x];
if(son[x]) dfs2(son[x], tp);
for(int v, i = fir[x]; ~i; i = e[i].nxt)
if((v=e[i].to) != fa[x] && v != son[x])
dfs2(v, v);
} namespace SegmentTree {
int sum[MAXN<<2], mx[MAXN<<2], mn[MAXN<<2];
bool rev[MAXN<<2];
inline void update(int i) {
sum[i] = sum[i<<1] + sum[i<<1|1];
mx[i] = max(mx[i<<1], mx[i<<1|1]);
mn[i] = min(mn[i<<1], mn[i<<1|1]);
}
inline void pushdown(int i) {
if(rev[i]) {
rev[i] ^= 1, rev[i<<1] ^= 1, rev[i<<1|1] ^= 1;
sum[i<<1] *= -1, sum[i<<1|1] *= -1;
swap(mx[i<<1], mn[i<<1]);
mx[i<<1] *= -1, mn[i<<1] *= -1;
swap(mx[i<<1|1], mn[i<<1|1]);
mx[i<<1|1] *= -1, mn[i<<1|1] *= -1;
rev[i] = 0;
}
}
void build(int i, int l, int r) {
if(l == r) {
mx[i] = mn[i] = sum[i] = w[l];
return;
}
int mid = (l + r) >> 1;
build(i<<1, l, mid);
build(i<<1|1, mid+1, r);
update(i);
}
void modify(int i, int l, int r, int x, int y) {
if(l == r) {
mx[i] = mn[i] = sum[i] = y;
return;
}
pushdown(i);
int mid = (l + r) >> 1;
if(x <= mid) modify(i<<1, l, mid, x, y);
else modify(i<<1|1, mid+1, r, x, y);
update(i);
}
void cover(int i, int l, int r, int x, int y) {
if(l == x && r == y) {
rev[i] ^= 1;
sum[i] *= -1;
swap(mx[i], mn[i]);
mx[i] *= -1, mn[i] *= -1;
return;
}
pushdown(i);
int mid = (l + r) >> 1;
if(y <= mid) cover(i<<1, l, mid, x, y);
else if(x > mid) cover(i<<1|1, mid+1, r, x, y);
else cover(i<<1, l, mid, x, mid), cover(i<<1|1, mid+1, r, mid+1, y);
update(i);
}
int querysum(int i, int l, int r, int x, int y) {
if(l == x && r == y) return sum[i];
pushdown(i);
int mid = (l + r) >> 1, res = 0;
if(y <= mid) res = querysum(i<<1, l, mid, x, y);
else if(x > mid) res = querysum(i<<1|1, mid+1, r, x, y);
else res = querysum(i<<1, l, mid, x, mid) + querysum(i<<1|1, mid+1, r, mid+1, y);
update(i);
return res;
}
int querymx(int i, int l, int r, int x, int y) {
if(l == x && r == y) return mx[i];
pushdown(i);
int mid = (l + r) >> 1, res = -INF;
if(y <= mid) res = querymx(i<<1, l, mid, x, y);
else if(x > mid) res = querymx(i<<1|1, mid+1, r, x, y);
else res = max(querymx(i<<1, l, mid, x, mid), querymx(i<<1|1, mid+1, r, mid+1, y));
update(i);
return res;
}
int querymn(int i, int l, int r, int x, int y) {
if(l == x && r == y) return mn[i];
pushdown(i);
int mid = (l + r) >> 1, res = INF;
if(y <= mid) res = querymn(i<<1, l, mid, x, y);
else if(x > mid) res = querymn(i<<1|1, mid+1, r, x, y);
else res = min(querymn(i<<1, l, mid, x, mid), querymn(i<<1|1, mid+1, r, mid+1, y));
update(i);
return res;
}
} inline void Invert(int x, int y) {
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
SegmentTree::cover(1, 1, n, dfn[top[x]], dfn[x]);
x = fa[top[x]];
}
if(x == y) return;
if(dep[x] < dep[y]) swap(x, y);
SegmentTree::cover(1, 1, n, dfn[y]+1, dfn[x]);
} inline int Sum(int x, int y) {
int res = 0;
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
res += SegmentTree::querysum(1, 1, n, dfn[top[x]], dfn[x]);
x = fa[top[x]];
}
if(x == y) return res;
if(dep[x] < dep[y]) swap(x, y);
res += SegmentTree::querysum(1, 1, n, dfn[y]+1, dfn[x]);
return res;
} inline int Max(int x, int y) {
int res = -INF;
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
res = max(res, SegmentTree::querymx(1, 1, n, dfn[top[x]], dfn[x]));
x = fa[top[x]];
}
if(x == y) return res;
if(dep[x] < dep[y]) swap(x, y);
res = max(res, SegmentTree::querymx(1, 1, n, dfn[y]+1, dfn[x]));
return res;
} inline int Min(int x, int y) {
int res = INF;
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
res = min(res, SegmentTree::querymn(1, 1, n, dfn[top[x]], dfn[x]));
x = fa[top[x]];
}
if(x == y) return res;
if(dep[x] < dep[y]) swap(x, y);
res = min(res, SegmentTree::querymn(1, 1, n, dfn[y]+1, dfn[x]));
return res;
} int main() {
memset(fir, -1, sizeof fir);
read(n);
for(int x, y, z, i = 1; i < n; ++i)
read(x), read(y), read(z), Add(x+1, y+1, z, i);
dfs(1); dfs2(1, 1);
SegmentTree::build(1, 1, n);
read(m);
int x, y; char s[2];
while(m--) {
while(!isalpha(s[0]=getchar())); s[1] = getchar();
read(x), read(y);
if(s[0] == 'S') printf("%d\n", Sum(x+1, y+1));
else if(s[0] == 'M' && s[1] == 'A') printf("%d\n", Max(x+1, y+1));
else if(s[0] == 'M' && s[1] == 'I') printf("%d\n", Min(x+1, y+1));
else if(s[0] == 'C') SegmentTree::modify(1, 1, n, dfn[bel[x]], y);
else Invert(x+1, y+1);
}
}

BZOJ 2157: 旅游 (树链剖分+线段树)的更多相关文章

  1. bzoj 2157: 旅游【树链剖分+线段树】

    裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio& ...

  2. BZOJ2157旅游——树链剖分+线段树

    题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路 ...

  3. BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )

    BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...

  4. BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)

    BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...

  5. BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)

    前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...

  6. bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2852  Solved: 1668[Submit][Sta ...

  7. BZOJ 3589 动态树 (树链剖分+线段树)

    前言 众所周知,90%90\%90%的题目与解法毫无关系. 题意 有一棵有根树,两种操作.一种是子树内每一个点的权值加上一个同一个数,另一种是查询多条路径的并的点权之和. 分析 很容易看出是树链剖分+ ...

  8. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  9. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  10. BZOJ2243 (树链剖分+线段树)

    Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...

随机推荐

  1. ./configure配置的参数 交叉编译 host,build target的含义

    交叉编译 host,build target的含义:build就是你正在使用的机器,host就是你编译好的程序可以运行的平台,target就是你编译的程序可以处理的平台.这个 build和host比较 ...

  2. Java实现二叉树地遍历、求深度和叶子结点的个数

    一.分析 二叉树是n个结点所构成的集合,它或为空树,或为非空树.对于非空树,它有且仅有一个根结点,且除根结点以外的其余结点分为两个互不相交的子集,分别称为左子树和右子树,它们本身又都是二叉树. 显而易 ...

  3. JavaScript设计模式(装饰者模式)

    一.模拟传统面向对象语言的装饰者模式: 假设我们在编写一个飞机大战的游戏,随着经验值的增加,我们操作的飞机对象可以升级成更厉害的飞机,一开始这些飞机只能发射普通的子弹,升到第二级时可以发射导弹,升到第 ...

  4. html常用代码大全

    1.结构性定义 文件类型 <HTML></HTML> (放在档案的开头与结尾) 文件主题 <TITLE></TITLE> (必须放在「文头」区块内) 文 ...

  5. PHP获取某段文字作为标题

    <?php mb_internal_encoding('utf-8'); // 提取文字标题,多余文字用省略号替换 $arr=[ '用心用情用功,进行无愧于时代的文艺创造', '一图了解第二届一 ...

  6. 【Git的基本操作十】远程库分支操作

    远程库分支操作 1. 推送分支 在本地库新建分支 git branch [新分支名] 如创建一个develop分支: git branch develop 推送分支(将新分支发布在github上) g ...

  7. CentOS 7自动以root身份登录GNOME桌面

    CentOS 7自动以root身份登录GNOME桌面 修改配置文件 /etc/gdm/custom.conf,在 [daemon] 下面添加一下两行 AutomaticLoginEnable=true ...

  8. Jetson TX1 安装ROS操作系统

    直接按照官网上的步骤安装即可,其中会出现很多bug,主要是依赖库安装的问题,添加清华源和中科大源,(注意:中科大源会有些问题)需要apt-get update 和 apt-get upgrade更新库 ...

  9. Linux 下幾種網芳/Samba 目錄的 mount 方式

      Linux 下幾種網芳/Samba 目錄的 mount 方式,比較新的 Smaba 只能用 cifs 的 mount 方式. [smbmount] smbmount -o username=&qu ...

  10. selenium:能够模拟人类打开浏览器的爬虫利器

    介绍 selenium相当于是一个机器人,可以模拟人类登陆浏览器的行为,比如点击.填充数据.删除cookie等等.Chromedriver是一个驱动Chrome的程序,使用它才可以驱动浏览器,其实Ch ...