CodeForces 838B Diverging Directions 兼【20180808模拟测试】t3

描述

给你一个图,一共有 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的并不敢发言)

内容概要:《2024年中国城市低空经济发展指数报告》由36氪研究院发布,指出低空经济作为新质生产力的代表,已成为中国经济新的增长点。报告从发展环境、资金投入、创新能力、基础支撑和发展成效五个维度构建了综合指数评价体系,评估了全国重点城市的低空经济发展状况。北京和深圳在总指数中名列前茅,分别以91.26和84.53的得分领先,展现出强大的资金投入、创新能力和基础支撑。低空经济主要涉及无人机、eVTOL(电动垂直起降飞行器)和直升机等产品,广泛应用于农业、物流、交通、应急救援等领域。政策支持、市场需求和技术进步共同推动了低空经济的快速发展,预计到2026年市场规模将突破万亿元。 适用人群:对低空经济发展感兴趣的政策制定者、投资者、企业和研究人员。 使用场景及目标:①了解低空经济的定义、分类和发展驱动力;②掌握低空经济的主要应用场景和市场规模预测;③评估各城市在低空经济发展中的表现和潜力;④为政策制定、投资决策和企业发展提供参考依据。 其他说明:报告强调了政策监管、产业生态建设和区域融合错位的重要性,提出了加强法律法规建设、人才储备和基础设施建设等建议。低空经济正加速向网络化、智能化、规模化和集聚化方向发展,各地应找准自身比较优势,实现差异化发展。
数据集一个高质量的医学图像数据集,专门用于脑肿瘤的检测和分类研究以下是关于这个数据集的详细介绍:该数据集包含5249张脑部MRI图像,分为训练集和验证集。每张图像都标注了边界框(Bounding Boxes),并按照脑肿瘤的类型分为四个类别:胶质瘤(Glioma)、脑膜瘤(Meningioma)、无肿瘤(No Tumor)和垂体瘤(Pituitary)。这些图像涵盖了不同的MRI扫描角度,包括矢状面、轴面和冠状面,能够全面覆盖脑部解剖结构,为模型训练提供了丰富多样的数据基础。高质量标注:边界框是通过LabelImg工具手动标注的,标注过程严谨,确保了标注的准确性和可靠性。多角度覆盖:图像从不同的MRI扫描角度拍摄,包括矢状面、轴面和冠状面,能够全面覆盖脑部解剖结构。数据清洗与筛选:数据集在创建过程中经过了彻底的清洗,去除了噪声、错误标注和质量不佳的图像,保证了数据的高质量。该数据集非常适合用于训练和验证深度学习模型,以实现脑肿瘤的检测和分类。它为开发医学图像处理中的计算机视觉应用提供了坚实的基础,能够帮助研究人员和开发人员构建更准确、更可靠的脑肿瘤诊断系统。这个数据集为脑肿瘤检测和分类的研究提供了宝贵的资源,能够帮助研究人员开发出更准确、更高效的诊断工具,从而为脑肿瘤患者的早期诊断和治疗规划提供支持。
### 获取Codeforces题目测试数据的方法 对于想要获取Codeforces题目的测试数据,通常有几种方法可以尝试: #### 使用官方资源 Codeforces本身提供了部分公开的测试案例,在比赛结束后可以通过查看提交记录中的Accepted解决方案来了解这些测试用例的结果。然而,完整的测试集通常是不对外公布的。 #### 参加比赛并分析反馈 当参与在线评测时,如果程序运行失败,系统会给出具体的错误发生在哪个测试点上,并提供该测试点的部分输入输出信息作为调试帮助[^1]。 #### 社区交流与讨论板 许多编程爱好者会在社区论坛或社交媒体平台上分享自己遇到的问题以及解决思路,有时也会包括一些有用的测试样例用于验证算法正确性[^2]。 #### 自定义生成器工具 为了更好地准备竞赛或者学习特定类型的题目,开发者们经常编写自己的随机数生成函数或者其他形式的数据制造脚本来模拟可能存在的边界条件和其他特殊情况下的表现情况。 ```python import random def generate_test_case(): max_value = int(2e5) n = random.randint(1, max_value) m = random.randint(1, max_value) print(f"Test Case Generated with N={n}, M={m}") generate_test_case() ``` 需要注意的是,虽然上述方式可以帮助理解问题和优化解答方案,但在实际比赛中应严格遵守平台规定,不得非法获取未授权访问权限内的任何资料。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值