luoguP1505旅游(处理边权的树剖)
/*
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旅游(处理边权的树剖)的更多相关文章
- BZOJ_2157_旅游_树剖+线段树
BZOJ_2157_旅游_树剖+线段树 Description Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但 ...
- 【BZOJ3999】【TJOI2015】旅游 树剖
题目大意 给你一棵树,有\(n\)个点.有\(q\)个操作,每次要你从\(x\)到\(y\)的路径上选两个点,使得距离\(x\)比较远的点的点权\(-\)距离\(x\)比较近的点的点权最大,然后把这条 ...
- BZOJ2157 旅游 【树剖 或 LCT】
题目 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路径. ...
- BZOJ 3626 [LNOI2014]LCA:树剖 + 差分 + 离线【将深度转化成点权之和】
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3626 题意: 给出一个n个节点的有根树(编号为0到n-1,根节点为0,n <= 50 ...
- BZOJ3999 [TJOI2015]旅游 【树剖 + 线段树】
题目 为了提高智商,ZJY准备去往一个新世界去旅游.这个世界的城市布局像一棵树.每两座城市之间只有一条路径可 以互达.每座城市都有一种宝石,有一定的价格.ZJY为了赚取最高利益,她会选择从A城市买入再 ...
- HihoCoder1576 子树中的最小权值( dfs序 +线段树 || 树剖)
给定一棵N个节点的树,编号1~N.其中1号节点是根,并且第i个节点的权值是Vi. 针对这棵树,小Hi会询问小Ho一系列问题.每次小Hi会指定一个节点x,询问小Ho以x为根的子树中,最小的权值是多少.为 ...
- P1505 [国家集训队]旅游[树剖]
题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路 ...
- B - Housewife Wind POJ - 2763 树剖+边权转化成点权
B - Housewife Wind POJ - 2763 因为树剖+线段树只能解决点权问题,所以这种题目给了边权的一般要转化成点权. 知道这个以后这个题目就很简单了. 怎么转化呢,就把这个边权转化为 ...
- 【BZOJ 3626】 [LNOI2014]LCA【在线+主席树+树剖】
题目链接: TP 题解: 可能是我比较纱布,看不懂题解,只好自己想了…… 先附一个离线版本题解[Ivan] 我们考虑对于询问区间是可以差分的,然而这并没有什么卵用,然后考虑怎么统计答案. 首先LC ...
随机推荐
- Java控制台打印三角形
for (int i = 1; i <= 5; i++) { //最上面先是五个往下一次4.3.2.1 for (int j = 5; j >= i; j--) { System.out. ...
- KingbaseES V8R6集群同步模式synchronous参数配置详解
如下图所示: 集群数据同步原理说明: synchronous参数配置测试: 集群节点信息: ID | Name | Role | Status | Upstream | repmgrd | PID | ...
- RabbitMQ之消息模式简单易懂,超详细分享~~~
前言 上一篇对RabbitMQ的流程和相关的理论进行初步的概述,如果小伙伴之前对消息队列不是很了解,那么在看理论时会有些困惑,这里以消息模式为切入点,结合理论细节和代码实践的方式一起来学习. 正文 常 ...
- TortoiseSVN 执行清理( cleanUp )失败的解决方案
TortoiseSVN 执行清理( cleanUp )失败的解决方案 今天碰到了一个比较棘手的问题,在这里做一下记录,以方便自己和有需要的朋友在之后碰到该类问题时有个参考. 现象 更新SVN时弹出清理 ...
- Web 开发相关概念
Web 开发相关概念 前端 后端 全栈 前端 Front-end:网站中用户看到的部分 HTML CSS JavaScript 库和框架 设计工具 后端 Back-end:网站中用户看不到的部分 编程 ...
- 【学习笔记】GBDT算法和XGBoost
前言 这一篇内容我学了足足有五个小时,不仅仅是因为内容难以理解, 更是因为前面CART和提升树的概念和算法本质没有深刻理解,基本功不够就总是导致自己的理解会相互在脑子里打架,现在再回过头来,打算好好总 ...
- 使用 Traefik 代理 UDP 服务
文章转载自:https://mp.weixin.qq.com/s?__biz=MzU4MjQ0MTU4Ng==&mid=2247488836&idx=1&sn=740f9aac ...
- python中限定导入的子模块
如果包定义文件__init__.py中存在一个叫做__all__的列表变量,那么在使用from package import *的时候就把这个列表中的所有名字作为要导入的模块名. 例如在example ...
- Fluentd部署详解
Fluentd系统配置项 https://www.cnblogs.com/sanduzxcvbnm/p/13920972.html Fluentd自身日志 https://www.cnblogs.co ...
- 1_Maven
一. 引言 1.1 项目管理问题 项目中jar包资源越来越多, jar包的管理越来越沉重 1.1.1 繁琐 要为每个项目手动导入所需的jar, 需要搜集全部的jar 1.1.2 复杂 项目中的jar如 ...