zoj 3649 树上的倍增法

树上倍增 对于在树上查找某点的祖先,如果简单的查找时间复杂度是o(n),那么,我们可以通过倍增算法优化这个时间复杂度,将每次跳一个点变成,每次跳2的i次方个点,也就是倍增优化这个过程,将时间复杂度变为o(logn)。 如何进行倍增? 首先我们需要进行一遍dfs初始化,处理出每个点的深度。根据深度,初始化fa[now][i],fa数组存的是now节点的2得i次方倍祖先。 这样处理完成后,我们来看树上倍增... 阅读详情

Social Net

Time Limit: 5 Seconds      Memory Limit: 65536 KB

There are n individuals(2 <= n <= 30000). Everyone has one or more friends. And everyone can contact all people by friend-relation. If two persons aren't friends, they also can contact by their friends. Each pair of friends have a friendship value ai(1 <= ai <= 50000).

Firstly, you will relieve some friend-relation. The rest of the friend-relation is the social net. The net is unique in all test cases. In this net, everyone can contact all people by rest friend-relation. The net has a minimum number of friend-relation. And the net has maximum sum of friendship value. We want to get the maximum sum.

Secondly, everyone has an angry value bi(1 <= bi <= 100000). We have q operations(1 <= q <= 30000): Person X wants to contact person Y, this operation merely has one sequence which describes the process. The sequence consists of persons' angry value. The persons are on the process.

We suppose the sequence is c1, c2, c3, ... ,ci. Here ci means the angry value of the ith people in the sequence.

We attempt to find the maximum ck-cj (ck >= cj, j <= k).

Example:

The sequence is 3(X), 4, 5, 6, 7, 5, 9, 4, 11(Y). The maximum ck-cj is 11-3=8.

The sequence is 3(X), 4, 5, 6, 7, 5, 9, 2, 11(Y). The maximum ck-cj is 11-2=9.

The sequence is 3(X), 10, 2, 5(Y). The maximum ck-cj is 10-3=7.

Input

The input contains multiple test cases. Each test case begins with a line containing a single integer n. The following line contains n integers bi.

The subsequent line describe the number of relations m(n <= m <= 50000). The next m lines contain the information about relations: x, y, ai. Their friendship value is ai.

Afterward gives q. The next q lines contain the operations: x, y. person X wants to contact person Y.

Output

For each case, print maximum sum of friendship value of the net on the first line.

The next q lines contain the answers of every operations.

Sample Input
6
3 5 1 7 3 5
7
1 2 5
1 3 6
2 4 7
2 5 8
3 6 9
4 5 1
5 6 2
5
6 1
6 2
6 3
6 4
6 5
Sample Output
35
2
4
0
6
4

第一问求最小生成树模板。第二问,每个节点有个ci值,查询树上节点u到v路径上(经过LCA)的点ci-cj(i>j)的最大值。

第二问麻烦就在于是树上的查询。先考虑简单的情形,假如生成的树是一条链,就变成rmq问题了,查询区间[l,r] ci-cj(i>=j)的最大值, 最大值要么是i<=m在[l,m]区间上,要么是j>m在[m+1,r]上,要么就是i>m,j<=m,在中间上等于右边区间最大值减去左边区间的最小值。所以假如用线段树之类rmq算法,线段树节点应该维护三个值,节点所代表的md[i]-ci-cj最大值,mi[i]-节点区间的最小值,mx[i]-节点区间的最大值。

但是线段树并不能直接用在树上,而还有一个rmq算法就是st算法,其原理就是倍增法,利用了二进制的思想。其实倍增法求树的最近公共祖先也类似于区间查询,知道了[l,m]的祖先(par[i][k])和[m+1,r]的祖先(par[par[i][k]][k]),那么就知道了[l,r]的祖先(par[i][k+1]),par[i][k]代表第i个节点的第2^k个祖先。

所以这道题需要维护的就是md[i][k],mdd[i],mi[i][k],mx[i][k],分别代表第i个节点开始到其第2^k个祖先这段序列的最大ci-cj值,最大cj-ci值,最小ci值,最大ci值。这里md[i]和mdd[i],一个是从下往上走,一个是从上往下走,因为这道题需要考虑走的方向,比如查询(u,v)和(v,u)方向是刚好相反的,所以要维护两个方向的。

但是树上的倍增法和st算法一样,支持区间查询操作但无法支持修改操作。其中对应的区间查询应该满足知道[l,m]和[m+1,r]的值,就能O(1)求的[l,r]对应的值。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
#define maxn 30005
#define maxv 16
#define inf 0x3f3f3f3f
typedef pair<int, int> p;
struct edge;
vector<edge> g[maxn];
int md[maxn][maxv], mdd[maxn][maxv], mi[maxn][maxv], mx[maxn][maxv];
int par[maxn][maxv];
int c[maxn], d[maxn];
int n,m,M;

struct edge
{
    int u,v,w;
    edge(){}
    edge(int uu, int vv, int ww){ u=uu;v=vv;w=ww;}
    bool operator <(const edge &a) const
    {
        return w>a.w;
    }
};
edge e[2*maxn];
int father[maxn]; //并查集用于kruskal
int find(int u)
{
    return u==father[u]?u:(father[u]=find(father[u]));
}

void unite(int u, int v)
{
    u=find(u);
    v=find(v);
    father[v]=u;
}

int vis[maxn];
void dfs(int u, int p, int dep)
{
    vis[u]=1;
    d[u]=dep;
    par[u][0]=p;
    if(p==-1){
        md[u][0]=0;
        mdd[u][0]=0;
        mi[u][0]=mx[u][0]=c[u];
    }
    else{
        md[u][0]= max(0, c[p]-c[u]);
        mdd[u][0]=max(0, c[u]-c[p]);
        mi[u][0]=min(c[p], c[u]);
        mx[u][0]=max(c[p], c[u]);
    }
    int v,w;
    for(int i=0; i<g[u].size(); i++){
        v=g[u][i].v, w=g[u][i].w;
        if(vis[v]) continue;
        dfs(v, u, dep+1);
    }
}

void init()
{
    for(int i=0; i<=n; i++) father[i]=i, g[i].clear();
    for(int i=1; i<=n; i++) scanf("%d", c+i);
    scanf("%d", &m);
    for(int i=0; i<m; i++)
        scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
    sort(e, e+m);

    int cnt=0;
    int res=0;
    for(int i=0; i<m && cnt<n-1; i++){  //kruskal最小生成树
        int u=e[i].u, v=e[i].v, w=e[i].w;
        if(find(u)==find(v)) continue;
        g[u].push_back(edge(u, v, w));
        g[v].push_back(edge(v, u, w));
        unite(u, v);
        res+=w;
        cnt++;
    }
    printf("%d\n", res);

    memset(vis, 0, sizeof(vis));
    for(int i=1; i<=n; i++)
        if(!vis[i])
        dfs(i,-1, 0);

    M=0;
    for(int i=1; i<=n; i++)
        M=max(d[i], M);
    M=ceil(log(M)/log(2));
    for(int v=1; v<=M; v++)
    for(int i=1; i<=n; i++){//初始化
       if(par[i][v-1]==-1){
            par[i][v]=-1;
            md[i][v]=md[i][v-1];
            mdd[i][v]=mdd[i][v-1];
            mx[i][v]=mx[i][v-1];
            mi[i][v]=mx[i][v-1];
       }
       else{
            int p=par[i][v-1];
            par[i][v]=par[p][v-1];
            mx[i][v]=max(mx[i][v-1], mx[p][v-1]);
            mi[i][v]=min(mi[i][v-1], mi[p][v-1]);
            md[i][v]=max(max(md[i][v-1], md[p][v-1]) ,mx[p][v-1]-mi[i][v-1]);
            mdd[i][v]=max(max(mdd[i][v-1], mdd[p][v-1]), mx[i][v-1]-mi[p][v-1]);
       }
    }
}

int lca(int u, int v)//求出最近公共祖先
{
    if(d[u]>d[v]) swap(u,v);

    for(int k=0; k<=M && d[v]!=d[u]; k++){
        if( (d[v]-d[u])>>k&1)
        v=par[v][k];

    }

    if(u==v) return u;
    for(int k= M; k>=0; k--){
        if(par[u][k] != par[v][k])
            u=par[u][k], v=par[v][k];
    }

    return par[u][0];
}

//md代表从下往上区间的最大差值,mdd代表从上往下的区间最大差值
//u,lca,v。假如u在v的左边。
//则需要查询(u,lca)的最大md值,和(lca,v)的最大mdd值,和((lca,v)的最大值-(u,lca)的最小值)。
p getmd(int u, int v) 
{
    if(u==v) return p(0, inf);
    int res=0, mini=c[u];
    for(int k=0; k<=M && d[v]!=d[u]; k++){
        if( (d[u]-d[v])>>k &1){ //利用二进制原理,比如往上走3步==00000011,等走2^0+2^1步
            res=max(md[u][k], res);
            res=max(res, mx[u][k]-mini);
            mini=min(mi[u][k], mini);
            u=par[u][k];
        }
    }

    return p(res, mini);  //返回最大md值,和区间最小值
}

p getmdd(int u, int v)
{
    if(u==v) return p(0, -inf);

    int res=0, maxi=c[u];
    for(int k=0; k<=M && d[v]!=d[u]; k++){
        if( (d[u]-d[v])>>k &1){
            res=max(mdd[u][k], res);
            res=max(res, maxi-mi[u][k]);
            maxi=max(maxi, mx[u][k]);
            u=par[u][k];
        }
    }

    return p(res, maxi);
}

int main()
{
    while(scanf("%d", &n)==1){
        init();
        int q;
        scanf("%d", &q);
        int u,v;
        while(q--){
            scanf("%d%d", &u, &v);
            int anc=lca(u,v);
            p t1=getmd(u, anc);
            p t2=getmdd(v, anc);
            int ans=0;
            
            ans=max(t1.first, t2.first);
            ans=max(ans, t2.second-t1.second);
            printf("%d\n", ans);

        }
    }
    return 0;
}


一步步教你离线安装vsftpd并配置FTP服务 在安装vsftpd之前,需确保系统更新至最新版本,并检查防火墙配置以允许FTP流量。安装过程涉及使用包管理器(如apt-get或yum)下载vsftpd及其依赖包,特别是在离线环境中,需先下载所有相关包并传输到目标机器。安装完成后,通过命令验证安装并启动服务。配置vsftpd包括编辑配置文件以设置访问权限和安全性参数,如匿名访问和本地用户访问。此外,需配置防火墙开放FTP端口,并通过FTP客户端测试服务。最后,建议进行安全配置,如禁用匿名访问和配置SSL/TLS加密,并设置日志记录以监控服务状态。 阅读详情

相关推荐

用Gazebo仿真无人机视觉SLAM:ORB-SLAM2+RGB-D相机完整调试记录

本文详细介绍了在Gazebo仿真环境中优化ORB-SLAM2用于无人机视觉SLAM的完整调试过程。通过定制传感器配置、调整ORB-SLAM2参数以及优化点云处理策略,显著提升了无人机在仿真环境中的SLAM性能。文章还提供了实用的调试技巧和性能评估方法,帮助开发者高效实现无人机视觉SLAM系统的仿真测试。

weixin_30485379的博客 448

树上倍增求链上最大值或最小值

倍增求链上点最大值 inline int LCA(int x,int y) { int maxn=max(w[x],w[y]); if (deep[x]>deep[y]) swap(x,y); int k=log2(deep[y]); for (int i=k;i>=0;i--) if (deep[f[i][y]]>=deep[x...

weixin_30527323的博客 730

数据结构:五岔路口交通管理红绿灯设计

我们可以知道这是一个“图”的着色问题,首先要考虑,为什么可行路线是13条?当然可以通过穷举得出,如果用公式:则是: 或者 因为一条路线必须包括一出一进两个方向 第一种答案的解法: 一、固定E为入口,则有C_4^1=4的可能; 二、除去E(因为E只有一个入向),剩下ABCD四个路口,然后因为C只有一个出方向,所以从剩下 的ABD中选择一个入口,即C_3^1; 三、再从剩下的三个出口任选

潘猫猫的世界 1万+

树上倍增法

最近公共祖先

实践求真知 1333

具身智能的边缘计算核心构成方案

摘要: 具身智能(Embodied Intelligence)依赖物理实体与环境交互,而边缘计算(Edge Computing)通过本地化数据处理降低延迟、提升实时性。两者结合的核心方案包含五层架构:传感器层采集环境数据,边缘处理单元执行本地计算,通信模块实现低延迟传输,决策引擎运行轻量AI模型,执行器接口转化动作为物理操作。该方案以“边缘优先”为原则,满足毫秒级响应(如延迟<50ms),同时优化能效(功耗降低30%)和隐私保护。适用于机器人、自动驾驶等场景,通过分层闭环设计确保在资源受限环境中的可靠

老郑的博客 810

【Hyper-V】虚拟机网络配置全解析:从端口映射到固定IP实战

本文全面解析Hyper-V虚拟机网络配置,从理解虚拟交换机三种模式(外部、内部、专用)的底层逻辑入手,指导用户创建稳定的内部/NAT网络,并详细演示如何在Linux与Windows虚拟机中配置固定IP。文章进一步深入讲解端口映射原理与netsh命令实战,以及双网卡配置和PowerShell自动化脚本等高级技巧,帮助用户彻底解决虚拟机网络“失联”问题,实现灵活可控的网络环境。

weixin_29290947的博客 269

图论算法:树上倍增法解决LCA问题(例题+cpp)

就是把每个 节点的 第 2^j 个的祖先找出来,用于之后的处理,同时我们还需要记录每个节点的。走一条边规定为走了一步,j可以表示为 0 ,1,2 ,分别代表走了 1步,2步,4步。一样,二分是缩小范围的,而倍增是扩大的,因此倍增与二分都具有。可以发现倍增是呈 2的指数型递增的一类数据,和。的时间复杂度,对于求解某些问题是非常高效的。,分别为1:节点6;2:节点5,4:节点1。,我们采用递归的形式,每次递归,走了四步:超过了范围,因此。走了一步: 到达了节点6。走了两步: 到达了节点5。什么是树的公共祖先?

ylh的博客 1766

PID详解

1、什么是PID及其作用 设定一个输出目标,反馈系统传回输出值,如与目标不一致,则存在一个误差,PID 根据此误差调整输入值,直至输出达到设定值. 为什么需要PID呢,比如控制温度,我们需要设置一个要达到的目标温度值,当将温度稳定在目标温度值 例如,我们希望水的目标温度值为70°,其希望无非就是可以快速而且无抖动的达到70°,并稳定在70° 如果我们使用普通的方式加热,当温度到达70°后就以及停止加热,岂不是简单快速,当然用在要求不高的场合也可以,但是如果要求更高的场合呢,会出现温度到达70°后......

weixin_48435215的博客 5万+

02 最近公共祖先(LCA)树上倍增法(附代码实现模板)

最近公共祖先(LCA) 最近公共祖先解决的问题 给定一颗有根树,若节点z即是节点x的祖先,也是节点y的祖先,则称z是x,y的公共祖先。 在x,y的所有公共祖先中,深度最大(距离根节点的距离最远的)的一个称为x,y的最近公共祖先,记作LCA(x,y)。 LCA(x,y)是x到根的路径与y到根的路径的交会点。它也是x与y之间的路径上深度最小的节点。求最近公共祖先的方法通常有以下三种。 方法1 向上标记法 从 x 向上走到根节点,并标记所有经过的节点。 从y向上从到根节点,当第一次遇到已经标记的节点时,就找到了

q2090988808的博客 1285

汽车行业OTD业务模式入门学习

本文是在学习彭俊松老师的《汽车行业整车订单交付系统》后,对于OTD理解的一些摘录,供诸位参考学习。

qq_40664711的博客 1万+

深入C++学习还必须掌握的一基础知识精讲

施磊C++语言基础提高课程笔记,包括了new/delete;malloc/free;引用和指针;const,指计和引用的结合;函数重载,inline的数,参数带默认值的函数;函数模板等知识点

GeniusAng的博客 1477

深度剖析倍增算法求解最近公共祖先(LCA)的细枝末节

LCA的求解算法较多,本文详细介绍了倍增算法解决LCA问题中的细枝末节。

y6123236的专栏 729

开源鸿蒙具身机器人(ROS2框架):从内核驱动到智能算法的完整实践

本指导文档旨在为开发者提供完整的开源鸿蒙(OpenHarmony)具身机器人开发解决方案,涵盖从底层驱动到上层ROS2应用的全栈开发流程。文档结合OpenHarmony内核驱动移植技术和ROS2机器人操作系统,为具身机器人开发提供详细的技术指导。具身机器人(Embodied Robot)是指具有物理实体、能够感知环境并与之交互的智能机器人系统。感知-决策-执行闭环多模态传感器融合(视觉、听觉、触觉、力觉)实时环境感知与理解智能决策与规划精确运动控制执行具身智能特性物理世界交互能力。

m0_67505153的博客 1268

zoj 3649 lca 倍增 DP

下课后直接奔实验室,月赛都快结束了,我擦,随便挑了一道题开始搞起来,是我喜欢的图论,心里暗暗欣喜,可是还是有点绕人,比赛结束刚好敲完,吃晚饭后,调了调,AC,呵呵 比赛的时候A的貌似很少,其实也不太难 链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3649 下面是我做过的倍增法求LCA以及倍增的DP的两个练习题

努力奋斗才能梦想成真 2076

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

ZOJ 3649 Social Net

前言 这题鸽了有一段时间了,今天上午自己想了想,冒出了一个不错的思路,而且似乎和之前听做过的同学讲的不太一样。然后就开始敲了,编译完马上过样例。交上去WA,TLE,各种错误接连而至。一直到刚刚,才结束了半天多的Debug,发现是快读打挂了…(逃…) 这是一个极其惨痛的教训。 题意 给你有N个节点的树,每个点都有一个权值。有Q个询问,每次询问从一个点走到另一个点,问你走过节点的序列c1,...

CaptainSlow 339

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

ZOJ 3649 Social Net(树上倍增)

一整天基本上只打了两题,每题半天,调起来简直爽爆。 There are n individuals(2 &lt;= n &lt;= 30000). Everyone has one or more friends. And everyone can contact all people by friend-relation. If two persons aren’t friends, they...

xyyxyyx的博客 271

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

最近公共祖先(LCA)之树上倍增法

最近公共祖先对于有根树T的两个结点u,v,最近公共祖先LCA(T,u,v)表示一个节点x,满足x是u,v的祖先并且x的深度尽可能大。 也可以把T理解为一个无向无环图,而LCA(T,u,v)即u到v的最短路上森度最小的点所以,LCA主要就是求解当两个点仅有唯一一条确定的最短路径时的路径信息的问题。树上倍增如果我们直接一个一个结点遍历去寻找这样的祖先,复杂度是O(n)的。而在算法竞赛中,经常会有个数较

Feynman1999的博客 976

树上倍增的写法和应用(详细讲解,新手秒懂)

最近做了一些树上的练习题,发现倍增真的是一种处理树上问题的神奇、方便的方法。 我以前一直打树链剖分打得多,但是学了倍增之后就再也不想打树链剖分了(当然有些题目不得不打)。 倍增比起树链剖分,代码短,容易查错,时空复杂度也优很多(nlogn),只是功能有些欠缺。 倍增的思想是二进制。         首先开一个n×logn的数组,比如fa[n][logn],其中fa[i][j]表示i

Saramanda的博客 1万+

最近公共祖先之树上倍增求法

一、问题引入 最近公共祖先(LCA)是求有根树上两点的深度最低的祖先节点,如下图,点5和点2的最近公共祖先为点4,点5和点3的最近公共祖先为点1,点5和点1的最近公共祖先为点1。 二、朴素算法 知道LCA定义后考虑最暴力的求解方法,可以先让在下面的点一层一层往上爬,直到两点具有相同深度(高度),之后两点同时一层一层往上爬,直到两点相同,这个相同的点就是最近公共祖先,若有m次询问,该算法时间复杂度为O(nm),显然过于暴力了。 三、树上倍增算法 朴素算法中找祖先节点都是一层一层地找,这样

Cloth的博客 680

最近公共祖先LCA算法——倍增法实现

什么是最近公共祖先?权威定义:对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。简而言之:在一棵没有环的树上,两个节点向上追溯,首次相遇的节点位置,就是这两个节点的最近公共祖先文字不好描述,下面以图来说明:如图所示,在左图中,节点4和节点6的最近公共祖先是节点1,在右图中,节点6和节点7的最近公共祖先是节点3。

qq_71450730的博客 1631

[zoj3649]Social Net

here are n individuals(2 <= n <= 30000). Everyone has one or more friends. And everyone can contact all people by friend-relation. If two persons aren’t friends, they also can contact by their friends.

Rec.的博客 467

ZOJ 3649 倍增法DP、树链剖分、tarjan并查集

Time Limit:5000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu Submit Status Practice ZOJ 3649 Description There are n individuals(2 n <= 30000). Everyone has one or more

Mr.Phoebe的专栏 869

Social Net ZOJ - 3649

题意 给出一幅有n个点的连通图,求出它的最大生成树,之后对于m个询问,每个询问包括两个数ab,求出a到b的路径上的极差最大值(必须用后面的数来减前面的) 方法 首先求出最大生成树,之后找到LCA,即可由它得到路径,但是发现暴力扫整一条路径肯定会TLE,因而可以用倍增的方法来预处理 dad[i][j]表示i节点的第(1 &amp;lt;&amp;lt; j)的父节点(即父节点的父节点的父节点,重复(1&amp;lt...

yzyyylx的博客 408

ZOJ 3649

倍增法DP #include #include #include #define N 50100 #define POW 17 #define inf 1000000 using namespace std; int val[N]; int head[N],cnt; int p[N][POW],dep[N],mi[N][POW],mx[N][POW],dp[N][POW],dp1[N][PO

1292765944的专栏 950

RMQ ZOJ 3649 Social Net

Social Net     Time Limit: 5 Seconds      Memory Limit: 65536 KB     There are n individuals(2  n <= 30000). Everyone has one or more friends. And everyone can contact all people by friend-r

We Can 788

树上倍增的应用

树上倍增的应用 归根到底,树上倍增的应用就是求LCA RMQ + 树上深搜 int fa[N][20]; int toUsed = 1; struct node{ int to; int nxt; }p[N*2]; void mkedge(int u,int v){ p[toUsed].to = v; p[toUsed].nxt = head[u]; ...

long1的博客 1286
上一篇: hdu 2255 二分图最大权匹配 km算法模板
下一篇: hdu 4738 边双连通&桥,有重边情况
HuanTongH
博客等级 码龄12年 7粉丝 110原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值