HDU3078 Network (倍增LCA算法求树链)

题意:

一棵无向树,输入点数和操作数,下面一行n个值代表每个点的权。下面n-1行是树边 操作分为 0 x w ,表示把点x的权改为w; k a b , 求出,从a到b的路径中,第k大的点权

题解:

对于每组询问,先求出两点的LCA,再从两点分别向LCA遍历,保存路径上所有的点权,排序输出第K大即可~

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=1e5+10;
int N,M,Q;
int t[maxn];
int cnt=0;
int head[maxn];
int tol;
struct node {
    int u;
    int v;
    int w;
    int next;
}edge[maxn*2];
void addedge (int u,int v) {
    edge[tol].u=u;
    edge[tol].v=v;
    edge[tol].next=head[u];
    head[u]=tol++;
}
int weight[maxn];
int d[maxn];
int h[maxn];
int father[20][maxn];
void dfs (int x) {
    for (int i=head[x];i!=-1;i=edge[i].next) {
        int v=edge[i].v;
        if (v==father[0][x]) continue;
        father[0][v]=x;
        h[v]=h[x]+1;
        dfs(v);
    }
}
int lca (int x,int y) {
    if (h[x]<h[y]) swap(x,y);
    for (int i=17;i>=0;i--)
        if (h[x]-h[y]>>i) x=father[i][x];
    if (x==y) return x;
    for (int i=17;i>=0;i--) {
        if (father[i][x]!=father[i][y]) {
            x=father[i][x];
            y=father[i][y];
        }
    }
    return father[0][x];
}
int main () {
    scanf("%d%d",&N,&Q);
    memset(head,-1,sizeof(head));
    for (int i=1;i<=N;i++)
        scanf("%d",&weight[i]);
    for (int i=0;i<N-1;i++) {
        int u,v;
        scanf("%d%d",&u,&v);
        addedge(u,v);
        addedge(v,u);
    }
    dfs(1);
    for (int i=1;i<=17;i++)
        for (int j=1;j<=N;j++)
            father[i][j]=father[i-1][father[i-1][j]];
    for (int i=0;i<Q;i++) {
        int k,x,y;
        scanf("%d%d%d",&k,&x,&y);
        if (k==0) weight[x]=y;
        else {
            int r=lca(x,y);
            cnt=0;
            while (x!=r) {
                t[cnt++]=weight[x];
                x=father[0][x];
            }
            while (y!=r) {
                t[cnt++]=weight[y];
                y=father[0][y];
            }
            t[cnt++]=weight[r];
            sort(t,t+cnt);
            if (cnt<k) {
                printf("invalid request!\n");
                continue;
            }
            printf("%d\n",t[cnt-k]);
        }
    }
}

原文地址:https://www.cnblogs.com/zhanglichen/p/12527160.html

时间: 2025-01-05 19:23:32

HDU3078 Network (倍增LCA算法求树链)的相关文章

【bzoj1146】[CTSC2008]网络管理Network 倍增LCA+dfs序+树状数组+主席树

题目描述 M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高速光缆组成.每个部门都有一个专属的路由器,部门局域网内的所有机器都联向这个路由器,然后再通过这个通信子网与其他部门进行通信联络.该网络结构保证网络中的任意两个路由器之间都存在一条直接或间接路径以进行通信. 高速光缆的数据传输速度非常快,以至于利用光缆传输的延迟时间可以忽略.但是由于路由器老化,在这些

洛谷P3379 【模板】最近公共祖先(LCA)(树链剖分)

题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入样例#1: 复制 5 5 4 3 1 2 4

XCOJ 1103 (LCA+树链最大子段和)

题目链接: http://xcacm.hfut.edu.cn/problem.php?id=1103 题目大意:链更新.链查询,求树链的最大子段和.(子段可以为空) 解题思路: 将所有Query离线存储,并且注明哪个是更新,哪个是查询. Tarjan离线处理中,记录每个结点的前驱,p[v]=u. 若更新,从u点回溯到LCA,从v点回溯到LCA,逐个修改. 若查询,将u点回溯到LCA,LCA,v点回溯到LCA的倒序拼成一个序列,求最大子段和. 值得注意的是,子段和全为负值的时候,ans=max(0

【模板时间】◆模板&#183;II◆ 树链剖分

[模板·II]树链剖分 学长给我讲树链剖分,然而我并没有听懂,还是自学有用--另外感谢一篇Blog +by 自为风月马前卒+ 一.算法简述 树链剖分可以将一棵普通的多叉树转为线段树计算,不但可以实现对一棵子树的操作,还可以实现对两点之间路径的操作,或是求 LCA(看起来很高级). 其实树链剖分不算什么特别高难的算法,它建立在 LCA.线段树.DFS序 的基础上(如果不了解这些算法的还是先把这些算法学懂再看树链剖分吧 QwQ).又因为树链剖分的基础算法不难,树链剖分的题也逐渐被引入 OI 赛中.

Luogu P3384 【模板】树链剖分

传送门~ 树链剖分,顾名思义,就是把树分成链. 通过这个方法,可以优化对树上两点间路径.某一点子树的修改和查询的操作,等. 流程 $dfs1()$ 在这个函数中,要处理出每个节点的: 深度dep[] 父亲fa[] 大小siz[] 重儿子编号hson[] 一个节点的siz[],是包括它自己.它的儿子.它儿子的儿子……一共的节点数量. 所谓的重儿子,就是一个节点的儿子中,siz[]最大的那一个. 叶子节点没有儿子,所以也没有重儿子. 这个函数就是普通的遍历整棵树,每到一个点记录dpth[],siz[

HDU5840 (分块+树链剖分)

Problem This world need more Zhu 题目大意 给一颗n个点的有点权的树,有m个询问,对于每个询问u,v,k,首先将点u到点v的最短路径上的所有点按顺序编号,u的编号为1,求树链上所有点的新编号cnt满足cnt%k==0的点的权值的最大值. n,m,k<=10^5 解题分析 根据k的大小分成两部分处理.原问题可转化为 deep[i] % k = a / b . 对于k较大的,直接暴力,按照dfs序用一个栈记录下所经过的点,对于每个询问的点不停往上爬. 对于k较小的,将

[GDOI2016] 疯狂动物园 [树链剖分+可持久化线段树]

题面 太长了,而且解释的不清楚,我来给个简化版的题意: 给定一棵$n$个点的数,每个点有点权,你需要实现以下$m$个操作 操作1,把$x$到$y$的路径上的所有点的权值都加上$delta$,并且更新一个版本 操作2,对于有向路径$(x,y)$上的点$a_i$,求下面的和值: $\sum_{i=1}^{len} a_i \sum_{j=1}^{len-i} j$ 操作3,回到第$i$个版本(但是下一次更新以后还是到总版本号+1的那个版本) 思路 这个题显然一眼就是树剖+可持久化数据结构啊 那么核心

bzoj 1036 树的统计Count (树链剖分+线段树)

题目大意:给你一棵树,每个点都有点权 有3种操作,修改某节点的权值,求树链上节点的权值的最大值,求树链上节点的权值和 树剖裸题,搜一个树链剖分序,用线段树维护一下即可,总时间 1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <queue> 5 #define inf 0x3f3f3f3f 6 #define ll long long 7 #define N

P3398 仓鼠找sugar(树链剖分)

P3398 仓鼠找sugar 题目描述 小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n.地下洞穴是一个树形结构.这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而他的基友同时要从他的卧室(c)到图书馆(d).他们都会走最短路径.现在小仓鼠希望知道,有没有可能在某个地方,可以碰到他的基友? 小仓鼠那么弱,还要天天被zzq大爷虐,请你快来救救他吧! 输入输出格式 输入格式: 第一行两个正整数n和q,表示这棵树节点的个数和询问的个数. 接下来n-1行,每行两个正整