/*
luogu1505
非常简单的处理边权的树剖题。
在树上将一条边定向,把这条边的权值赋给这条边的出点
树剖的时候不计算lca权值即可
*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int h=200010;
//线段树部分
ll a[h];
struct node{
int l,r;
ll val,mx,mn;
ll lz;
}tree[h*4];
void pushup(int root){
tree[root].val=tree[root*2].val+tree[root*2+1].val;
tree[root].mx=max(tree[root*2].mx,tree[root*2+1].mx);
tree[root].mn=min(tree[root*2].mn,tree[root*2+1].mn);
}
void build(int root,int l,int r){
tree[root].l=l,tree[root].r=r,tree[root].lz=1;
tree[root].mx=-1010,tree[root].mn=1010;
if(l==r){
tree[root].mx=a[l];
tree[root].mn=a[l];
tree[root].val=a[l];
return;
}
int mid=(l+r)/2;
build(root*2,l,mid);
build(root*2+1,mid+1,r);
pushup(root);
}
void pushdown(int root){//存储区间取反
if(tree[root].lz==1)
return;
tree[root*2].val*=tree[root].lz;
tree[root*2+1].val*=tree[root].lz; swap(tree[root*2].mx,tree[root*2].mn);
tree[root*2].mx*=-1;
tree[root*2].mn*=-1; swap(tree[root*2+1].mx,tree[root*2+1].mn);
tree[root*2+1].mx*=-1;
tree[root*2+1].mn*=-1; tree[root*2].lz*=tree[root].lz;
tree[root*2+1].lz*=tree[root].lz; tree[root].lz=1;
}
ll query_sum(int root,int l,int r){//区间和
if(tree[root].l>=l&&tree[root].r<=r)
return tree[root].val;
pushdown(root);
int mid=(tree[root].l+tree[root].r)/2;
ll ans=0;
if(mid>=l)
ans+=query_sum(root*2,l,r);
if(mid<r)
ans+=query_sum(root*2+1,l,r);
return ans;
}
ll query_max(int root,int l,int r){//区间最大
if(tree[root].l>=l&&tree[root].r<=r)
return tree[root].mx;
pushdown(root);
int mid=(tree[root].l+tree[root].r)/2;
ll ans=-1010;//这里要设成负数,因为边的权值可能全是负数
if(mid>=l)
ans=max(ans,query_max(root*2,l,r));
if(mid<r)
ans=max(ans,query_max(root*2+1,l,r));
return ans;
}
ll query_min(int root,int l,int r){//区间最小
if(tree[root].l>=l&&tree[root].r<=r)
return tree[root].mn;
pushdown(root);
int mid=(tree[root].l+tree[root].r)/2;
ll ans=1010;
if(mid>=l)
ans=min(ans,query_min(root*2,l,r));
if(mid<r)
ans=min(ans,query_min(root*2+1,l,r));
return ans;
}
void change(int root,int p,ll x){//单点修改
if(tree[root].l==tree[root].r){
tree[root].mx=tree[root].mn=tree[root].val=x;
return;
}
pushdown(root);
int mid=(tree[root].l+tree[root].r)/2;
if(mid>=p)
change(root*2,p,x);
else
change(root*2+1,p,x);
pushup(root);
}
void turn(int root,int l,int r){//区间取反
if(tree[root].l>=l&&tree[root].r<=r){
tree[root].mx*=-1,tree[root].mn*=-1;
swap(tree[root].mx,tree[root].mn);
tree[root].val*=-1;
tree[root].lz*=-1;
return;
}
pushdown(root);
int mid=(tree[root].l+tree[root].r)/2;
if(mid>=l)
turn(root*2,l,r);
if(mid<r)
turn(root*2+1,l,r);
pushup(root);
}
int head[h],last[h],to[h],tot=0;
void add_edge(int x,int y){
tot++;
last[tot]=head[x];
head[x]=tot;
to[tot]=y;
}
void add(int x,int y){
add_edge(x,y);
add_edge(y,x);
}
int n,m,roots;
//树剖部分
ll w[h];
int fa[h],siz[h],dep[h],mxs[h],dfn[h],top[h],td=0;
void dfs1(int now,int f){
fa[now]=f,siz[now]=1;
for(int i=head[now];i;i=last[i]){
int nex=to[i];
if(nex==f)
continue;
dep[nex]=dep[now]+1;
dfs1(nex,now);
siz[now]+=siz[nex];
if(siz[nex]>siz[mxs[now]]||!mxs[now])
mxs[now]=nex;
}
}
void dfs2(int now,int from){
dfn[now]=++td,a[td]=w[now],top[now]=from;
if(mxs[now])
dfs2(mxs[now],from);
for(int i=head[now];i;i=last[i]){
int nex=to[i];
if(nex==fa[now]||nex==mxs[now])
continue;
dfs2(nex,nex);
}
}
void pturn(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])
swap(x,y);
turn(1,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
if(dep[x]>dep[y])
swap(x,y);
if(x!=y)
turn(1,dfn[x]+1,dfn[y]);//这一步操作左端是dfn[x]+1,因为lca的权值代表的边不在路径内
}
ll pquery_sum(int x,int y){
ll ans=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])
swap(x,y);
ans+=query_sum(1,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
if(dep[x]>dep[y])
swap(x,y);
if(x!=y)
ans+=query_sum(1,dfn[x]+1,dfn[y]);//同上
return ans;
}
ll pquery_min(int x,int y){
ll ans=1010;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])
swap(x,y);
ans=min(ans,query_min(1,dfn[top[x]],dfn[x]));
x=fa[top[x]];
}
if(dep[x]>dep[y])
swap(x,y);
if(x!=y)
ans=min(ans,query_min(1,dfn[x]+1,dfn[y]));
return ans;
}
ll pquery_max(int x,int y){
ll ans=-1010;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])//这里注意里面是top
swap(x,y);
ans=max(ans,query_max(1,dfn[top[x]],dfn[x]));
x=fa[top[x]];
}
if(dep[x]>dep[y])
swap(x,y);
if(x!=y)
ans=max(ans,query_max(1,dfn[x]+1,dfn[y]));
return ans;
} struct edge{
int p1,p2,out;
ll len;
}e[h];
int main(){
scanf("%d",&n);
//题目里的点从0开始,我们为了方便操作,将所有点加1,从1开始
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u+1,v+1);
e[i].p1=u+1,e[i].p2=v+1;
scanf("%lld",&e[i].len);
}
dfs1(1,0);
for(int i=1;i<n;i++){//给边定向
if(fa[e[i].p2]==e[i].p1)
e[i].out=e[i].p2,w[e[i].p2]=e[i].len;
else
e[i].out=e[i].p1,w[e[i].p1]=e[i].len;
}
dfs2(1,1);
build(1,1,td);
scanf("%d",&m);
for(int i=1;i<=m;i++){
string op;
cin>>op;
if(op=="C"){
int ed;
ll ch;
scanf("%d%lld",&ed,&ch);
change(1,dfn[e[ed].out],ch);
}
if(op=="N"){
int x,y;
scanf("%d%d",&x,&y);
pturn(x+1,y+1);
}
if(op=="SUM"){
int x,y;
scanf("%d%d",&x,&y);
printf("%lld\n",pquery_sum(x+1,y+1));
}
if(op=="MAX"){
int x,y;
scanf("%d%d",&x,&y);
printf("%lld\n",pquery_max(x+1,y+1));
}
if(op=="MIN"){
int x,y;
scanf("%d%d",&x,&y);
printf("%lld\n",pquery_min(x+1,y+1));
}
}
return 0;
}

luoguP1505旅游(处理边权的树剖)的更多相关文章

  1. BZOJ_2157_旅游_树剖+线段树

    BZOJ_2157_旅游_树剖+线段树 Description Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但 ...

  2. 【BZOJ3999】【TJOI2015】旅游 树剖

    题目大意 给你一棵树,有\(n\)个点.有\(q\)个操作,每次要你从\(x\)到\(y\)的路径上选两个点,使得距离\(x\)比较远的点的点权\(-\)距离\(x\)比较近的点的点权最大,然后把这条 ...

  3. BZOJ2157 旅游 【树剖 或 LCT】

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

  4. BZOJ 3626 [LNOI2014]LCA:树剖 + 差分 + 离线【将深度转化成点权之和】

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3626 题意: 给出一个n个节点的有根树(编号为0到n-1,根节点为0,n <= 50 ...

  5. BZOJ3999 [TJOI2015]旅游 【树剖 + 线段树】

    题目 为了提高智商,ZJY准备去往一个新世界去旅游.这个世界的城市布局像一棵树.每两座城市之间只有一条路径可 以互达.每座城市都有一种宝石,有一定的价格.ZJY为了赚取最高利益,她会选择从A城市买入再 ...

  6. HihoCoder1576 子树中的最小权值( dfs序 +线段树 || 树剖)

    给定一棵N个节点的树,编号1~N.其中1号节点是根,并且第i个节点的权值是Vi. 针对这棵树,小Hi会询问小Ho一系列问题.每次小Hi会指定一个节点x,询问小Ho以x为根的子树中,最小的权值是多少.为 ...

  7. P1505 [国家集训队]旅游[树剖]

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

  8. B - Housewife Wind POJ - 2763 树剖+边权转化成点权

    B - Housewife Wind POJ - 2763 因为树剖+线段树只能解决点权问题,所以这种题目给了边权的一般要转化成点权. 知道这个以后这个题目就很简单了. 怎么转化呢,就把这个边权转化为 ...

  9. 【BZOJ 3626】 [LNOI2014]LCA【在线+主席树+树剖】

    题目链接: TP 题解:   可能是我比较纱布,看不懂题解,只好自己想了…… 先附一个离线版本题解[Ivan] 我们考虑对于询问区间是可以差分的,然而这并没有什么卵用,然后考虑怎么统计答案. 首先LC ...

随机推荐

  1. 第九十八篇:Web的储存机制LocalStorage

    好家伙 1.什么是LocalStorage? LocalStorage 是一种 web 端的存储机制, 它使得由 JavaScript 编写的网站或者应用可以无限期的在浏览器中存储并访问数据. Loc ...

  2. 《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(20)-Fiddler精选插件扩展安装,让你的Fiddler开挂到你怀疑人生

    1.简介 Fiddler本身的功能其实也已经很强大了,但是Fiddler官方还有很多其他扩展插件功能,可以更好地辅助Fiddler去帮助用户去开发.测试和管理项目上的任务.Fiddler已有的功能已经 ...

  3. 好书推荐之Mysql三剑客 :《高性能Mysql》、《Mysql技术内幕》、《数据库索引设计与优化》

    Mysql三剑客系列书籍: 大佬推荐 首先推荐<高性能 MySQL>,这本书是 MySQL 领域的经典之作,拥有广泛的影响力.不但适合数据库管理员(DBA)阅读,也适合开发人员参考学习.不 ...

  4. Flink基础概念入门

    Flink 概述 什么是 Flink Apache Apache Flink 是一个开源的流处理框架,应用于分布式.高性能.高可用的数据流应用程序.可以处理有限数据流和无限数据,即能够处理有边界和无边 ...

  5. std:move() 作用 和 移动语义后 右值行为,unique_ptr的"移动"操作问题

    unique_ptr 不能进行赋值操作,但是可以有返回unique_ptr的函数,由此产生的问题: 结论1:std:move() 只是将一个实参强行转换为右值引用. 我们知道对象初始化时有 构造函数, ...

  6. NLP新手入门指南|北大-TANGENT

    开源的学习资源:<NLP 新手入门指南>,项目作者为北京大学 TANGENT 实验室成员. 该指南主要提供了 NLP 学习入门引导.常见任务的开发实现.各大技术教程与文献的相关推荐等内容, ...

  7. 【项目实战】自备相机+IMU跑通Vins-Mono记录

    前言 初次接触SLAM,公司要求用自己的设备来跑通vinsmono这个程序,虽然已经跑通了别人的数据包,但是真正自己上手来运行这个程序,发现真的是困难重重,特意在此记载下来整个过程,以供大家参考. 我 ...

  8. Ingress-nginx灰度发布功能详解

  9. MinIO客户端快速入门指南

    官方文档地址:http://docs.minio.org.cn/docs/master/minio-client-quickstart-guide MinIO Client (mc)为ls,cat,c ...

  10. 第二章:视图层 - 9:动态生成CSV文件

    CSV (Comma Separated Values),以纯文本形式存储数字和文本数据的存储方式.纯文本意味着该文件是一个字符序列,不含必须像二进制数字那样的数据.CSV文件由任意数目的记录组成,记 ...