洛谷.4114.Qtree1(树链剖分)

题目链接
模板题都错了这么多次。。

//边权赋到点上 树剖模板
//注意LCA、链的顶端不能统计到答案!
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int N=1e5+5;

int n,m,cnt,ep[N],W[N],id[N],sz[N],dep[N],son[N],fa[N],top[N],Enum,H[N],to[N<<1],nxt[N<<1],val[N<<1];
struct Seg_Tree
{
    int A[N],mx[N<<2];
    inline void PushUp(int rt) {mx[rt]=std::max(mx[rt<<1],mx[rt<<1|1]);}
    void Build(int l,int r,int rt)
    {
        if(l==r) mx[rt]=A[l];
        else
        {
            int m=l+r>>1;
            Build(lson), Build(rson);
            PushUp(rt);
        }
    }
    void Modify(int l,int r,int rt,int p,int v)
    {
        if(l==r) mx[rt]=v;
        else
        {
            int m=l+r>>1;
            if(p<=m) Modify(lson,p,v);
            else Modify(rson,p,v);
            PushUp(rt);
        }
    }
    int Query_Max(int l,int r,int rt,int L,int R)
    {
        if(L<=l && r<=R) return mx[rt];
        int m=l+r>>1;
        if(L<=m)
            if(m<R) return std::max(Query_Max(lson,L,R),Query_Max(rson,L,R));
            else return Query_Max(lson,L,R);
        return Query_Max(rson,L,R);
    }
}t;
inline int read()
{
    int now=0,f=1;register char c=gc();
    for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now*f;
}
inline void AddEdge(int u,int v,int w)
{
    to[++Enum]=v, nxt[Enum]=H[u], val[Enum]=w, H[u]=Enum;
    to[++Enum]=u, nxt[Enum]=H[v], val[Enum]=w, H[v]=Enum;
}
void DFS1(int x)
{
    int mx=0; sz[x]=1;
    for(int v,i=H[x]; i; i=nxt[i])
        if((v=to[i])!=fa[x])
        {
            fa[v]=x, dep[v]=dep[x]+1, DFS1(v), sz[x]+=sz[v];
            W[v]=val[i], ep[i>>1]=v;
            if(mx<sz[v]) mx=sz[v], son[x]=v;
        }
}
void DFS2(int x,int tp)
{
    id[x]=++cnt, t.A[cnt]=W[x], top[x]=tp;
    if(son[x])
    {
        DFS2(son[x],tp);
        for(int i=H[x]; i; i=nxt[i])
            if(to[i]!=fa[x] && to[i]!=son[x])
                DFS2(to[i],to[i]);
    }
}
int Query_Chain(int x,int y)
{
    int res=0;
    while(top[x]!=top[y])//while(top[x]^top[y])
    {
        if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
        res=std::max(res,t.Query_Max(1,n,1,id[top[x]],id[x])), x=fa[top[x]];
    }
    if(x==y) return res;//LCA不统计入答案!
    if(dep[x]>dep[y]) std::swap(x,y);
    return std::max(res,t.Query_Max(1,n,1,id[son[x]]/*not id[x]!*/,id[y]));
}

int main()
{
    Enum=1;
    n=read();
    for(int u,v,w,i=1; i<n; ++i)
        u=read(),v=read(),w=read(),AddEdge(u,v,w);
    DFS1(1), DFS2(1,1);
    t.Build(1,n,1);
    char opt[7]; int x,y;
    while(scanf("%s",opt),opt[0]!='D')
    {
        x=read(),y=read();
        if(opt[0]=='C') t.Modify(1,n,1,id[ep[x]],y);
        else printf("%d\n",Query_Chain(x,y));;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/SovietPower/p/8446044.html

时间: 2024-08-29 19:07:47

洛谷.4114.Qtree1(树链剖分)的相关文章

洛谷 P3979 遥远的国度(树链剖分)

题目描述 修改某条路径上的值以及询问子树的最小值都是最树剖的基础操作,那么如何实现换根呢? 考虑一下三种情况: 1.rot=询问的子树x,答案就是整棵树的最小值 2.rot在x的子树里,只有rot到x这一条链上的的节点的子树会变 找到x在rot方向上的子节点,答案就是除去这棵子树的最小值 3.rot不在x的子树里,那么rot是谁对x的子树没有影响,答案不变 那么就在询问时分类讨论一下就好了 #include<complex> #include<cstdio> using names

Qtree1 - 树链剖分

树剖裸题?(复习练练手) 1 // luogu-judger-enable-o2 2 #include <bits/stdc++.h> 3 using namespace std; 4 5 int n,vis[100005],size[100005],dep[100005],fa[100005][20],val[100005],wson[100005],t1,t2,t3,t4,ind; 6 int tid[100005],sid[100005],top[100005],eg1[100005],

树链剖分[模板](洛谷 P3384)

洛谷·[模板]树链剖分 写在前面 首先,在学树链剖分之前最好先把 LCA.树形DP.DFS序 这三个知识点学了 如果这三个知识点没掌握好的话,树链剖分难以理解也是当然的. 树链剖分 树链剖分 就是对一棵树分成几条链,把树形变为线性,减少处理难度 概念 dfs1() dfs2() 对剖过后的树建线段树 处理问题 概念 重儿子:对于每一个非叶子节点,它的儿子中 儿子数量最多的那一个儿子 为该节点的重儿子 轻儿子:对于每一个非叶子节点,它的儿子中 非重儿子 的剩下所有儿子即为轻儿子 叶子节点没有重儿子

洛谷 P3384 【模板】树链剖分

题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和 操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z 操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和 输入输出格式 输入格式: 第一行包含4个正整数N.M.R.P,分别表示树的结点个数.操作个数

洛谷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

洛谷 P2590 树的统计 P3178 树上操作【树链剖分入门】

题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身 输入格式: 输入文件的第一行为一个整数n,表示节点的个数. 接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连

洛谷 P2146 [NOI2015]软件包管理器 (树链剖分模板题)

题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个软件包的安装所依赖的其它软件包),完成所有的配置.Debian/Ubuntu使用的apt-get,Fedora/CentOS使用的yum,以及OSX下可用的homebrew都是优秀的软件包管理器. 你决定设计你自己的软件包管理器.不可避免地,你要解决软件包之间的依赖问题.如果软件包A依赖软件包B,那

树链剖分(以维护线段树为例)

关于树链剖分的有关知识:http://www.cnblogs.com/sagitta/p/5660749.html 以下是洛谷p3384经过无数次WA和RE(最后发现只是有一个函数的调用写反了qwq)终于AC的代码: #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<climits> #in

树链剖分详解

前言 树链剖分是什么? 树链剖分,说白了就是一种让你代码不得不强行增加1k的数据结构-dms 个人理解:+1:joy: 有什么用? 证明出题人非常毒瘤 可以非常友(bao)好(li)的解决一些树上问题:grimacing: (友情提示:学树链剖分之前请先掌握线段树) 核心思想 树链剖分的思想比较神奇 它的思想是:把一棵树拆成若干个不相交的链,然后用一些数据结构去维护这些链 那么问题来了 如何把树拆成链? 首先明确一些定义 重儿子:该节点的子树中,节点个数最多的子树的根节点(也就是和该节点相连的点