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

题目描述

修改某条路径上的值以及询问子树的最小值都是最树剖的基础操作,那么如何实现换根呢?

考虑一下三种情况:

1.rot=询问的子树x,答案就是整棵树的最小值
2.rot在x的子树里,只有rot到x这一条链上的的节点的子树会变
找到x在rot方向上的子节点,答案就是除去这棵子树的最小值
3.rot不在x的子树里,那么rot是谁对x的子树没有影响,答案不变

那么就在询问时分类讨论一下就好了

#include<complex>
#include<cstdio>
using namespace std;
const int INF=1<<30;
const int N=1e5+7;
struct node{
    int v,nxt;
}e[N<<1];
int n,m,s,Enum,tim,rot;
int val[N],front[N],fa[N][20];
int fat[N],dep[N],tid[N],son[N],siz[N],top[N],rank[N];
int tree[N<<2],lazy[N<<2];
inline int qread()
{
    int x=0,j=1;
    char ch=getchar();
    while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)j=-1;ch=getchar();}
    while(ch>=‘0‘ && ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*j;
}
inline void Insert(int u,int v)
{
    e[++Enum].v=v;
    e[Enum].nxt=front[u];
    front[u]=Enum;
}
void dfs1(int x)
{
    siz[x]=1;
    fa[x][0]=fat[x];
    for(int i=front[x];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if(v==fat[x])continue;
        fat[v]=x;
        dep[v]=dep[x]+1;
        dfs1(v);
        siz[x]+=siz[v];
        if(siz[v]>siz[son[x]])
            son[x]=v;
    }
}
void dfs2(int x,int tp)
{
    top[x]=tp;
    tid[x]=++tim;
    rank[tid[x]]=x;
    if(!son[x])return;
    dfs2(son[x],tp);
    for(int i=front[x];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if(v!=son[x] && v!=fat[x])
            dfs2(v,v);
    }
}
inline void PushUp(int rt)
{
    tree[rt]=min(tree[rt<<1],tree[rt<<1|1]);
}
inline void PushDown(int rt)
{
    if(lazy[rt])
    {
        tree[rt<<1]=tree[rt<<1|1]=lazy[rt];
        lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
        lazy[rt]=0;
    }
}
void Build(int l,int r,int rt)
{
    if(l==r)
    {
        tree[rt]=val[rank[l]];
        return;
    }
    int mid=l+r>>1;
    Build(l,mid,rt<<1);
    Build(mid+1,r,rt<<1|1);
    PushUp(rt);
}
void Modify(int l,int r,int rt,int nowl,int nowr,int v)
{
    if(nowl<=l && r<=nowr)
    {
        tree[rt]=lazy[rt]=v;
        return;
    }
    PushDown(rt);
    int mid=l+r>>1;
    if(nowl<=mid)Modify(l,mid,rt<<1,nowl,nowr,v);
    if(mid<nowr)Modify(mid+1,r,rt<<1|1,nowl,nowr,v);
    PushUp(rt);
}
int Query(int l,int r,int rt,int nowl,int nowr)
{
    if(nowl<=l && r<=nowr)
        return tree[rt];
    PushDown(rt);
    int mid=l+r>>1,a=INF,b=INF;
    if(nowl<=mid)a=Query(l,mid,rt<<1,nowl,nowr);
    if(mid<nowr)b=Query(mid+1,r,rt<<1|1,nowl,nowr);
    return min(a,b);
}
void FindFather()
{
    for(int j=1;j<=19;j++)
        for(int i=1;i<=n;i++)
            fa[i][j]=fa[fa[i][j-1]][j-1];
}
inline int Lca(int a,int b)
{
    if(dep[a]<dep[b])swap(a,b);
    int tmp=dep[a]-dep[b];
    for(int i=19;i>=0;i--)
        if(tmp&(1<<i))
            a=fa[a][i];
    if(a==b)return a;
    for(int i=19;i>=0;i--)
        if(fa[a][i]!=fa[b][i])
        {
            a=fa[a][i];
            b=fa[b][i];
        }
    return fa[a][0];
}
inline void ModifyRoad(int x,int y,int v)
{
    int f1=top[x],f2=top[y];
    while(f1!=f2)
    {
        if(dep[f1]<dep[f2])swap(f1,f2),swap(x,y);
        Modify(1,n,1,tid[f1],tid[x],v);
        x=fat[f1];f1=top[x];
    }
    if(dep[x]>dep[y])swap(x,y);
    Modify(1,n,1,tid[x],tid[y],v);
}
inline int QueryTree(int x)
{
    if(x==rot)return tree[1];
    int lca=Lca(x,rot);
    if(lca==x)
    {
        int tmp=dep[rot]-dep[x]-1,v=rot;
        for(int i=0;i<=19;i++)
            if(tmp&(1<<i))
                v=fa[v][i];
        return min(Query(1,n,1,1,tid[v]-1),Query(1,n,1,tid[v]+siz[v],n));
    }
    return Query(1,n,1,tid[x],tid[x]+siz[x]-1);
}
int main()
{
    scanf("%d%d",&n,&m);
    int u,v,p,x;
    for(int i=1;i<=n-1;i++)
    {
        u=qread();v=qread();
        Insert(u,v);
        Insert(v,u);
    }
    for(int i=1;i<=n;i++)
        val[i]=qread();
    dfs1(1);dfs2(1,1);
    Build(1,n,1);
    FindFather();
    scanf("%d",&rot);
    for(int i=1;i<=m;i++)
    {
        p=qread();
        if(p==1)rot=qread();
        if(p==2)
        {
            u=qread();v=qread();x=qread();
            ModifyRoad(u,v,x);
        }
        if(p==3)
        {
            x=qread();
            printf("%d\n",QueryTree(x));
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/LeTri/p/8531082.html

时间: 2024-11-03 03:29:21

洛谷 P3979 遥远的国度(树链剖分)的相关文章

洛谷.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],

BZOJ 3083 遥远的国度 树链剖分

3083: 遥远的国度 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 797  Solved: 181[Submit][Status] Description 描述 zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀. 问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连

BZOJ 3083 遥远的国度 树链剖分+线段树

有换根的树链剖分的裸题. 在换根的时候注意讨论. 注意数据范围要开unsigned int或longlong #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<ctime> #include<string> #include<iomanip> #include<a

树链剖分[模板](洛谷 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,那

遥远的国度(树链剖分,换根)

遥远的国度 题目描述 zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀. 问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树.这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的.遥远的国度的每个城市有一个防御值,有些时候RapiD会使