描述

给你一个图,一共有 N 个点,2*N-2 条有向边。

边目录按两部分给出

1、 开始的 n-1 条边描述了一颗以 1 号点为根的生成树,即每个点都可以由 1 号点到达。

2、 接下来的 N-1 条边,一定是从 i 到 1(2<=i<=N)的有向边,保证每个点都能到达

有 q 次询问:

1 x w :表示将第 x 条边的边权修改为 w

2 u v :询问 u 到 v 的最短距离

【输入格式】

第一行是 2 个整数 N,Q,表示一共 N 个点 Q 次询问

接下来是 N-1 行,每行 3 个整数 U,V,W,表示了前 N-1 条边,u 到 v 的有向边

接下来 N-1 行,每行 3 个整数 U,V,W,描述了每个点到 1 号点的边,V==1

接下来是 Q 行,表示 Q 次修改与询问

【输出格式】

若干行,每行回答一次询问

【输入样例】

5 9

1 3 1

3 2 2

1 4 3

3 5 4

5 1 5

3 1 6

2 1 7

4 1 8

2 1 1

2 1 3

2 3 5

2 5 2

1 1 100

2 1 3

1 8 30

2 4 2

2 2 4

【输出样例】

0

1

4

8

100

132

10

第一反应,树链剖分+线段树,这么裸,欺负我昨天晚上才看的树剖板

诶等等?怎么会有边权?

然后这个只会敲板子的蒟蒻就懵逼掉了

然后今天蒟蒻的玄学贪心1分儿也没骗到

于是本蒟蒻成功爆0

关于正解

令 ai表示从 i 到根的边的长度。对于每个点维护 disti表示从根到 i 的路径, mindisti表示 i 的子树中 distj+aj的最小值。

然后对于询问 (u,v)分类:

如果 u 是 v的祖先,由于权值都是正整数,答案为distv−distu。

否则答案为mindistu−distu+distv。

dist和 mindist用 dfs序+线段树维护就可以了。

具体维护

维护子树 1->i->1 的值 dist,每个点记录第一次的 dfs 序 st[i],子树结束的 ed[i]

当边 u->v 修改为 w,则 st[v]…ed[v] 增加 w- w’,w’表示 u->v 原来的值。同时,当边 u->1 修改为 w:则 st[u]..st[u]增加 w-w’

好了,那么搬上代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 200010
using namespace std;
struct Edge{
int u,v,w,nxt;
}e[N<<1];
long long sum[N<<2],p[N<<2],dis[N],add[N<<2];
int dep[N],top[N],son[N],l[N],r[N],s[N],u[N],w[N],x1,y1,z1;
int h[N],tot;
int k,cnt=0,n,Q,a[N],L;
void addd(int x,int y,int z){
e[++cnt].u=x;e[cnt].v=y,e[cnt].w=z;e[cnt].nxt=h[x],h[x]=cnt,u[y]=x;
}
//以下dfs序与lca部分
void dfs1(int x,int y){
dep[x]=++y;l[x]=++tot;s[x]=1;w[tot]=x;
for(int i=h[x];i;i=e[i].nxt){
dis[e[i].v]=dis[x]+e[i].w;
dfs1(e[i].v,y);
s[x]+=s[e[i].v];
if(s[e[i].v]>s[son[x]])son[x]=e[i].v;
}
r[x]=tot;
}
void dfs2(int x,int y){
top[x]=y;
if(son[x])dfs2(son[x],y);
for(int i=h[x];i;i=e[i].nxt)
if(e[i].v!=son[x])dfs2(e[i].v,e[i].v);
}
int Lca(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]>dep[top[y]])
x=u[top[x]];
else y=u[top[y]];
}
return dep[x]>dep[y]?y:x;
}
//以下线段树部分(谢天谢地我终于搞出了没有结构体的线段树)
void Up(int x){
sum[x]=min(sum[x<<1],sum[x<<1|1]);
}
void Build(int x,int l,int r){
if(l==r){
sum[x]=dis[w[l]]+a[w[l]];
add[x]=dis[w[l]];
return;
}
int Mid=l+r>>1;
Build(x<<1,l,Mid);
Build(x<<1|1,Mid+1,r);
Up(x);
}
inline void Down(int x){
if(p[x]){
sum[x<<1]+=p[x];add[x<<1]+=p[x];p[x<<1]+=p[x];
sum[x<<1|1]+=p[x];add[x<<1|1]+=p[x];p[x<<1|1]+=p[x];
p[x]=0;
}
}
inline void Update1(int x,int l,int r,int y,int z){
if(l==r){
sum[x]+=z;
return;
}
Down(x);
int Mid=l+r>>1;
if(y<=Mid)Update1(x<<1,l,Mid,y,z);else Update1(x<<1|1,Mid+1,r,y,z);
Up(x);
}
inline void Update2(int x,int l,int r,int L,int R,int y){
if(l>R||r<L)return;
if(l>=L&&r<=R){
sum[x]+=y;add[x]+=y;p[x]+=y;
return;
}
Down(x);
int Mid=l+r>>1;
Update2(x<<1,l,Mid,L,R,y);Update2(x<<1|1,Mid+1,r,L,R,y);
Up(x);
}
long long Query(int x,int l,int r,int L,int R){
if(l>R||r<L)return 1e18;
if(l>=L&&r<=R)return sum[x];
Down(x);
int Mid=l+r>>1;
return min(Query(x<<1,l,Mid,L,R),Query(x<<1|1,Mid+1,r,L,R));
}
long long Query2(int x,int l,int r,int y){
if(l==r)return add[x];
Down(x);
int Mid=l+r>>1;
if(y<=Mid)return Query2(x<<1,l,Mid,y);
return Query2(x<<1|1,Mid+1,r,y);
}
int main(){
scanf("%d%d",&n,&Q);
for(int i=1;i<n;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
addd(x,y,z);
}
for(int i=1;i<n;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
e[++cnt].u=x;e[cnt].v=y;a[x]=z;
}
tot=0;
dfs1(1,0);
dfs2(1,1);
Build(1,1,n);
while(Q--){
scanf("%d%d%d",&k,&x1,&y1);
if(k==1){
if(x1>=n)Update1(1,1,n,l[e[x1].u],y1-a[e[x1].u]),a[e[x1].u]=y1;
else Update2(1,1,n,l[e[x1].v],r[e[x1].v],y1-e[x1].w),e[x1].w=y1;
}else{
L=Lca(x1,y1);
if(L==x1)printf("%lld\n",Query2(1,1,n,l[y1])-Query2(1,1,n,l[x1]));
else printf("%lld\n",Query(1,1,n,l[x1],r[x1])-Query2(1,1,n,l[x1])+Query2(1,1,n,l[y1]));
}
}
return 0;
}

我想我的代码比起某标程已经相当好看了,只要是知道线段树与树剖的结合题解都应该看得懂,除了个别变量名在改动时被懒惰的本蒟蒻张冠李戴之外没有什么难以理解的地方了。

ps(据说有隔壁巨佬3h就调好了还嫌慢我这个6h的并不敢发言)

CodeForces 838B Diverging Directions 兼【20180808模拟测试】t3的更多相关文章

  1. Codeforces 838B - Diverging Directions - [DFS序+线段树]

    题目链接:http://codeforces.com/problemset/problem/838/B You are given a directed weighted graph with n n ...

  2. 【20180808模拟测试】T2 k-斐波那契

    描述 k-斐波拉契数列是这样的 f(0)=k;f(1)=k;f(n)=(f(n-1)+f(n-2))%P(n>=2); 现在我们已经知道了f(n)=1,和P: k的范围是[1,P); 求k的所有 ...

  3. Codeforces 838 B - Diverging Directions

    B - Diverging Directions 思路: 用dfs序+线段树维护子树中距离(从1到u,再从u到1)的最小值 代码: #pragma GCC optimize(2) #pragma GC ...

  4. Android单元测试与模拟测试详解

    测试与基本规范 为什么需要测试? 为了稳定性,能够明确的了解是否正确的完成开发. 更加易于维护,能够在修改代码后保证功能不被破坏. 集成一些工具,规范开发规范,使得代码更加稳定( 如通过 phabri ...

  5. [开源]微信在线信息模拟测试工具(基于Senparc.Weixin.MP开发)

    目前为止似乎还没有看到过Web版的普通消息测试工具(除了官方针对高级接口的),现有的一些桌面版的几个测试工具也都是使用XML直接请求,非常不友好,我们来尝试做一个“面向对象”操作的测试工具. 测试工具 ...

  6. 安装nginx python uwsgi环境 以及模拟测试

    uwsgi帮助文档: http://uwsgi-docs-cn.readthedocs.io/zh_CN/latest/WSGIquickstart.html http://uwsgi-docs.re ...

  7. 「CF838B」 Diverging Directions

    B. Diverging Directions 题意 给出一个n个点2n-2条边的有向图.n-1条指向远离根方向的边形成一棵树,还有n-1条从非根节点指向根节点的边. q次操作,1修改第x条边权值为y ...

  8. 利用Python中的mock库对Python代码进行模拟测试

    这篇文章主要介绍了利用Python中的mock库对Python代码进行模拟测试,mock库自从Python3.3依赖成为了Python的内置库,本文也等于介绍了该库的用法,需要的朋友可以参考下     ...

  9. 转 C#实现PID控制的模拟测试和曲线绘图

    C#实现PID控制的模拟测试和曲线绘图   本文分两部分,一部分是讲PID算法的实现,另一部分是讲如何用动态的曲线绘制出PID运算的结果. 首先,PID算法的理论模型请参考自动控制理论,最早出现的是模 ...

随机推荐

  1. 工程命名为***&***出现的问题: LaunchScreen.xib: Line 20: EntityRef: expecting ';'

    今天新建一个项目命名为28 & 29. extern&static,  然后cmd + R运行,居然碰到了编译错误. 当时就奇怪了,怎么会这样呢?报错内容如下: 开始还以为新安装的Xc ...

  2. ASP.NET WebApi 中使用swagger 构建在线帮助文档

    1 在Visual Studio 中创建一个Asp.NET  WebApi 项目,项目名:Com.App.SysApi(本例创建的是 .net 4.5 框架程序) 2  打开Nuget 包管理软件,查 ...

  3. 课时53.video标签第二种格式(掌握)

    由于视频数据非常非常的重要,所以五大浏览器厂商都不愿意支持别人都视频格式,所以导致了没有一种视频格式是所有浏览器都支持的,这个时候W3C为了解决这个问题,所以推出了第二种video标签的格式 如何查看 ...

  4. Linux -- 用户组篇

    Linux -- 用户与用户组 1.Linux 系统中有三种角色:所有者(用户),用户组与其他人,一张图可以说明用户与用户组的关系. 如图,某公司相当于一个用户组,该用户组下有A,B两个用户,用户拥有 ...

  5. 浅谈React和VDom关系

    组件化 组件的封装 组件的复用 组件的封装 视图 数据 视图和数据之间的变化逻辑 import React, {Component} from 'react'; export default clas ...

  6. easyui 上 datagrid 的表头的checkbox全选时 取消选中 disabled的checkbox

    业务需求: 正常情况下,easyui的全选checkbox会选择表中全部的checkbox包括行.及时对checkbox加了disable属性也没有效果.但是现在的业务是当对checkbox加了dis ...

  7. Const 关键字详解

    const 标识符 在c++中作为常量修饰符 用来修饰 函数 变量  指针 const 修饰的变量不可以改变值 const 在修饰指针的时候 const 标识符出现在*的左边表示 指向的变量为常量不能 ...

  8. .Net core 使用Jenkins + Docker + Azure Devops 傻瓜式部署

    这几天一直在搞 Jenkins + Docker + Azure Devops 部署,因为这种方式部署真的非常的省心,而且速度快,方便快捷,等等无数优点,感谢我的单身领导的支持,当然也感谢 晓晨大神, ...

  9. jQuery获取Select option 选择的Text和 Value

    获取一组radio被选中项的值:var item = $('input[name=items][checked]').val();获取select被选中项的文本var item = $("s ...

  10. eclipse创建maven项目及Javaweb项目

    1.开启eclipse,右键new——>other,如下图找到maven project 2.选择maven project,显示创建maven项目的窗口 3.在搜索框中搜索“web”,选择,n ...