题目

【问题描述】

小迟生活的城市是⼀棵树(树指的是⼀个含有 \(n\) 个节点以及 \(n-1\) 条边的⽆向连通图),节点编号从 \(1\) 到 \(n\),每条边拥有⼀个权值 \(value\),表示通过这条边的时候你需要交纳的金钱(注意,有可能这个值为负数,也就是说你经过这条边的时候你可以赚钱)

小迟是⼀个杰出的马路工,他居住在节点 \(s\),他能够选择任意⼀个节点 \(m\),并将从节点 \(s\) 到节点 \(m\) 的简单路径(简单路径指的是不经过同⼀个节点两次)上的所有边的权值都修改为 \(0\).

现在小迟获得 \(q\) 个请求,每个请求都是以 \(a\) \(b\) 的形式给出,表示小迟的好朋友小早希望从节点 \(a\) 走简单路径到节点$ b$,小迟希望能最小化小早需要缴纳的钱。

需要注意的是,小迟获得的这 \(q\) 个请求是相互独立的,也就是说您只需要对于每⼀个请求,决定小迟的⼀个修路⽅案,使得小早需要缴纳的钱尽可能的少。

【输入格式】

输⼊⽂件名为 \(road.in\)。

第⼀行三个正整数为 \(n,q,s\)。

接下来 \(n-1\) 行,每行三个整数$ x$ \(y\) \(z\), 表示有⼀条边 \((x,y)\),\(value\) 为$ z$。

接下来 \(q\) 行,每行两个正整数 \(a\) \(b\),表示请求。

【输出格式】

输出⽂件名为 \(road.out\)。

\(q\) 行,每行⼀个整数,表示需要缴纳的最少的钱。

【样例输入】

3 2 1
1 2 1
2 3 1
1 2
1 3

【样例输出】

0
0

【样例解释】

对于第⼀次询问 \(1\) \(2\), ⼩迟可以修从 \(1\) 到 \(2\) 的路,从⽽使得⼩早不需要缴纳⾦钱;

对于第⼆次询问 \(1\) \(3\), ⼩迟可以修从 \(1\) 到 \(3\) 的路,从⽽使得⼩早不需要缴纳⾦钱。

【数据规模及约定】

对于 \(30\%\)的数据,\(n≤1000,q≤1000\).

对于 \(100\%\)的数据,\(1≤n,q≤200000,1≤x,y≤n,|z|≤1000\).

解法

首先考虑没有负权边的情况,显然只需要树链剖分维护,线段树维护区间和,回答询问时选取将两端点到\(s\)点的路径中,点权和较大的那一条修改为\(0\)权值即可.

然后考虑有负权边的情况.

我们可以以\(s\)为根节点建树,将每个点的权值设置为它到根节点的距离,记\(x\)为\(u \rightarrow v\)简单路径中点权最大的点,显然将\(s \rightarrow x\)路径中边设为\(0\)权值是最佳方案.要求这个最佳方案的缴纳钱数,需要用到\(LCA\).一个特殊情况是,如果\(x\)的权值为负,那么不删除为最佳方案.

综上,答案为

\[weight[u]+weight[v]-2*weight[x]-max(f(u,v)-weight[x],0
\]

其中\(f(u,v)\)表示\(u \rightarrow v\)简单路径中点权最大的点的点权.

代码

#include<cstdio>
#include<algorithm>
using namespace std;
const int SIZE=500005;
const int INF=0x3F3F3F3F; int n,q,s;
int weight[SIZE],weightx[SIZE],siz[SIZE],son[SIZE],dep[SIZE],Fa[SIZE],ID[SIZE],top[SIZE]; struct Tree
{
int L,R;
int sum,tag;
#define L(v) T[v].L
#define R(v) T[v].R
#define sum(v) T[v].sum
#define tag(v) T[v].tag
#define LC(v) (v*2)
#define RC(v) (v*2+1)
#define pushup(v) sum(v)=max(sum(LC(v)),sum(RC(v)))
}T[SIZE*4];
void Build(int p,int L,int R)
{
L(p)=L;R(p)=R;
if(L==R){sum(p)=weightx[L];return;}
int Mid=(L+R)>>1;
Build(LC(p),L,Mid);
Build(RC(p),Mid+1,R);
pushup(p);
} int query(int p,int L,int R)
{
if(L>R(p)||R<L(p))return -INF;
if(L<=L(p)&&R>=R(p))return sum(p);
return max(query(LC(p),L,R),query(RC(p),L,R));
} int head[SIZE],nex[SIZE],ver[SIZE],edge[SIZE],Tot=1;
void ins(int u,int v,int e){ nex[++Tot]=head[u]; head[u]=Tot; ver[Tot]=v; edge[Tot]=e; } void DFS1(int u,int Dis)
{
siz[u]=1;
weight[u]=Dis;
for(int i=head[u];i;i=nex[i])
{
int v=ver[i];
if(dep[v])continue;
dep[v]=dep[u]+1;
Fa[v]=u;
DFS1(v,Dis+edge[i]);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
} int Cnt=0;
void DFS2(int u,int TOP)
{
ID[u]=++Cnt;
weightx[Cnt]=weight[u];
top[u]=TOP;
if(siz[u]==1)return;
DFS2(son[u],TOP);
for(int i=head[u];i;i=nex[i])
{
int v=ver[i];
if(v==Fa[u]||v==son[u])continue;
DFS2(v,v);
}
} int f(int u,int v)
{
int Res=-INF;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])swap(u,v);
Res=max(Res,query(1,ID[top[u]],ID[u]));
u=Fa[top[u]];
}
if(dep[u]<dep[v])swap(u,v);
Res=max(Res,query(1,ID[v],ID[u]));
return Res;
} int LCA(int u,int v)
{
while(top[u]!=top[v])
dep[top[u]]<dep[top[v]]? v=Fa[top[v]] : u=Fa[top[u]];
return dep[u]<dep[v]? u : v;
} int main()
{
freopen("road.in","r",stdin);
freopen("road.out","w",stdout);
scanf("%d%d%d",&n,&q,&s);
int u,v,e;
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&u,&v,&e);
ins(u,v,e);
ins(v,u,e);
}
dep[s]=s;
DFS1(s,0);
DFS2(s,s);
Build(1,1,n);
while(q--)
{
scanf("%d%d",&u,&v);
int x=LCA(u,v);
printf("%d\n",weight[u]+weight[v]-2*weight[x]-max(f(u,v)-weight[x],0));
}
return 0;
}

马路 树链剖分/线段树/最近公共祖先(LCA)的更多相关文章

  1. jzoj4918. 【GDOI2017模拟12.9】最近公共祖先 (树链剖分+线段树)

    题面 题解 首先,点变黑的过程是不可逆的,黑化了就再也洗不白了 其次,对于\(v\)的祖先\(rt\),\(rt\)能用来更新答案当且仅当\(sz_{rt}>sz_{x}\),其中\(sz\)表 ...

  2. 【bzoj3626】[LNOI2014]LCA 树链剖分+线段树

    题目描述 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询 ...

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

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

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

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

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

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

  6. POJ3237 (树链剖分+线段树)

    Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...

  7. bzoj4034 (树链剖分+线段树)

    Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...

  8. HDU4897 (树链剖分+线段树)

    Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...

  9. Aizu 2450 Do use segment tree 树链剖分+线段树

    Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...

  10. 【POJ3237】Tree(树链剖分+线段树)

    Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...

随机推荐

  1. win10中Pycharm连接mysql时区错误的解决

    今天,突然想试下在win10中Django学习,好不容易把Mysql设置完毕,数据库也建好了,可连接测试通不过: Server returns invalid timezone. Go to 'Adv ...

  2. ssrf漏洞利用(内网探测、打redis)

    摘要:存在ssrf漏洞的站点主要利用四个协议,分别是http.file.gopher.dict协议. file协议拿来进行本地文件的读取,http协议拿来进行内网的ip扫描.端口探测,如果探测到637 ...

  3. Redis基础详解

    1. Redis是什么.特点.优势 Redis是一个开源的使用C语言编写.开源.支持网络.可基于内存亦可持久化的日志型.高性能的Key-Value数据库,并提供多种语言的API. 它通常被称为 数据结 ...

  4. vue router的其他属性、 值的传递 、 懒加载

    路由的router-link标签有几个其他属性: 路由可以传递值(一般用作条目的id传递,之后用这个id从axios获取页面显示的数据 第一步: 定义路由以及值的属性名称(之后在跳转路由后页面里面获取 ...

  5. ansi sql 语法 切换为 oracle 语法

        语句粘贴到 工作表 打开查询构建器 勾选 创建oracle连接 over     sql dev 的语法设置调整,否则表别名会右对齐   下面是 转换后的结果,是不是看得舒服多了

  6. POJ 2096 Collecting Bugs (概率DP,求期望)

    Ivan is fond of collecting. Unlike other people who collect post stamps, coins or other material stu ...

  7. new SparkContext()发生错误java.lang.NoSuchMethodError: scala.Predef

    参考:https://blog.csdn.net/weixin_40137479/article/details/80320324 new SparkContext(conf)发生错误: Except ...

  8. 杭电oj_2058——The sum problem(java实现)

    原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=2058 思路:等差数列公式变形:sum = a1 * len + len *(len -1)/2 抽象成 ...

  9. npm 升级到最新版本

    先npm -v查看自己的npm 是否是最新版本,如果不是则进入安装node的文件夹,可通过 where node 查找该文件夹. 进入之后使用: npm i npm -g 之后使用: npm -v 查 ...

  10. JavaScript 闭包浅析

    词法作用域 闭包 概念 作用 用法 待续 词法作用域 词法作用域是指一个变量在源码中声明的位置作为它的作用域.同时嵌套的函数可以访问到其外层作用域中声明的变量. 函数中的定义的局部变量只能由函数的内部 ...