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数组---数组的使用(打印,求和,最大值)
public static void main(String[] args) { int[] arrays={1,2,3,4,5}; //打印该数组 for (int i = 0; i < ar ...
- 从原理剖析带你理解Stream
摘要:Stream是jdk1.8给我们提供的新特性 本文分享自华为云社区<深入理解Stream之原理剖析>,作者: 李哥技术 . Stream是jdk1.8给我们提供的新特性,主要就是允许 ...
- SpringMVC 04: SpringMVC中4种页面跳转方式
转发和重定向的页面跳转方式 页面跳转方式,本质上只有2种方式:转发 + 重定向 但在SpringMVC的具体实现上,转发可以细分为:普通的页面转发 + 经由action方法的页面转发 重定向可以细分为 ...
- Sync包
sync同步包 Mutex互斥锁: 能够保证在同一时间段内仅有一个goroutine持有锁,有且仅有一个goroutine访问共享资源,其他申请锁的goroutine将会被阻塞直到锁被释放.然后重新争 ...
- 点赞和取消点赞实现Redis缓存(只思路)
思路:点赞.取消点赞 --> Redis --> (每两个小时)存到数据库(MySQL),所以就相当于每次查询或者存储都需要先经过Redis,而查询的目的是为了判断用户的点赞状态(已点赞o ...
- 【微服务】- 配置中心 - Nacos
微服务 - 配置中心 - Nacos 一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学习成长! 今天的学习任务就是学习使用Nacos作为配置中心. 努力克制自己,拒绝摆烂! 什么是配 ...
- 源码安装最新版keepalived,剥离日志出来并配置日志轮询
安装 yum install -y gcc openssl-devel popt-devel ipvsadm libnl3-devel net-snmp-devel libnl libnl-devel ...
- UDP协议编程
#接收代码 import socket # 使用IPV4协议,使用UDP协议传输数据 s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 绑定端口 ...
- liunx的三个时间atime,mtime,ctime详细说明与使用场景
导航:一.文件与文件夹三个时间:atime,mtime,ctime的含义二.ll命令查看文件时间三.stat命令查看文件的时间四.测试创建/修改文件的时间五.常用命令关于文件时间相关 - - - - ...
- MySQL 窗口函数
1. 窗口函数概念和语法 窗口函数对一组查询行执行类似聚合的操作.然而,聚合操作将查询行分组到单个结果行,而窗口函数为每个查询行产生一个结果: 函数求值发生的行称为当前行 与发生函数求值的当前行相关的 ...