描述

给你一个图,一共有 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. Multicast Routing

    Multicasting Source S sends packets to multicast group G1 (and minimize the number of copies) Revers ...

  2. HTML5视频播放插件 video.js介绍

    video.js是一款很流行的html5视频播放插件.很适合在移动端播放视频(比如微信网页),功能强大,且支持降级到flash,兼容ie8.官网:http://videojs.com/    git& ...

  3. Nlog日志出坑合集

    .net core框架下nlog不记录: 1.安装NLog.Web.AspNetCore 2.在Startup.cs文件的方法public void Configure(IApplicationBui ...

  4. JS中some(),every(),fiflter(),map()各种循环的区别理解

    1.some():返回一个Boolean,判断是否有元素符合func条件const arr = [1,2,3,4]; arr.some((item)=>{return item>1}) 打 ...

  5. Windows10:Opencv4.0+Opencv4.0.1_contrib编译

    操作系统:windows10 64bit 已安装工具:VS2017 64bit,cmake3.12bit. 安装Cmake:到cmake下载3.12及以上版本,64bit, 选择windows下的安装 ...

  6. #leetcode刷题之路7- 整数反转

    给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转. 示例 1:输入: 123输出: 321 示例 2:输入: -123输出: -321 示例 3:输入: 120输出: 21 #i ...

  7. Centos7.5 lnmp+mongodb扩展

    安装NginxYUM源中没有Nginx,我们需要增加一个nginx的源nginx.repo # vi /etc/yum.repos.d/nginx.repo 源文件的内容 [nginx] name=n ...

  8. 3D立方体

    效果图 主要用到的3D属性 1.保留子元素的3d属性:transform-style:preserve-3d; 2.2D变形属性: ①transform:translate()平移,分X轴,Y轴,Z轴 ...

  9. mysql 导出行数据到txt文件,指定字符分割

    select id,name, concat('tel:',phone) from user order by time INTO outfile 'user.txt' FIELDS terminat ...

  10. 大数据学习--day10(继承-权限-super-final-多态-组合)

    继承-权限-super-final-多态-组合 权限修饰符     内容         public         protected         default(不写就是它)         ...