[bzoj 3083]遥远的国度

本文介绍了一种在树形结构上进行的操作——树链剖分,并针对一种特殊情况即改根操作进行了详细的解析。文章通过实例讲解了如何处理改根后的查询与更新操作,包括如何快速找到最小防御值等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。RapiD想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。由于RapiD无法解决这个问题,所以他拦住了zcwwzdjn希望他能帮忙。但zcwwzdjn还要追杀sb的zhx,所以这个重大的问题就被转交到了你的手上。

这道题跟普通的树链剖分基本没什么区别,但是多了一个改根操作,这个一开始有一点吓到我了。但其实没有那么复杂,我们发现改根之后,对修改操作没有影响,直接做就可以了。可询问操作就要分情况讨论。
如果当前的根等于询问操作的x的话,那其实就是把全部的点给问一次。
如果当前的根跟x的lca不等于x,那其实是对x的子树是没有影响的,照常找它的子树就可以了。
但是如果lca为x,那就说明当前的根原本为x的子节点,那x的实际上的子树就会发生变化,但其实也没有多大变化,只要不查找当前的根所在的链(这条链的起始点为x的其中一个儿子),其他全部查询就可以了,不是很难想。
那这道题就解决了。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
struct node
{
    int x,y,next;
}a[210000];int len,last[110000];
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;
}
struct trnode
{
    int l,r,lc,rc,c,lazy;
}tr[210000];int trlen;
void bt(int l,int r)
{
    trlen++;int now=trlen;
    tr[now].l=l;tr[now].r=r;
    tr[now].lc=tr[now].rc=-1;
    if(l<r)
    {
        int mid=(l+r)/2;
        tr[now].lc=trlen+1;bt(l,mid);
        tr[now].rc=trlen+1;bt(mid+1,r);
    }
}
int son[110000],tot[110000],dep[110000],f[110000][20];
void pre_tree_node(int x)
{
    for(int i=1;(1<<i)<=dep[x];i++)f[x][i]=f[f[x][i-1]][i-1];
    son[x]=0;tot[x]=1;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=f[x][0])
        {
            f[y][0]=x;
            dep[y]=dep[x]+1;
            pre_tree_node(y);
            if(tot[son[x]]<tot[y])son[x]=y;
            tot[x]+=tot[y];
        }
    }
}
int id,ys[110000],top[110000];
void pre_tree_edge(int x,int tp)
{
    ys[x]=++id;top[x]=tp;
    if(son[x]!=0)pre_tree_edge(son[x],tp);
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=f[x][0] && y!=son[x])pre_tree_edge(y,y);
    }
}
void update(int now)
{
    int lc=tr[now].lc,rc=tr[now].rc;
    tr[lc].c=tr[now].lazy;tr[lc].lazy=tr[now].lazy;
    tr[rc].c=tr[now].lazy;tr[rc].lazy=tr[now].lazy;
    tr[now].lazy=0;
}
void change(int now,int l,int r,int k)
{
    if(tr[now].l==l && tr[now].r==r){tr[now].c=tr[now].lazy=k;return ;}
    if(tr[now].lazy!=0)update(now);
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(r<=mid)change(lc,l,r,k);
    else if(mid+1<=l)change(rc,l,r,k);
    else change(lc,l,mid,k),change(rc,mid+1,r,k);
    tr[now].c=min(tr[lc].c,tr[rc].c);
}
int findmin(int now,int l,int r)
{
    if(tr[now].l==l && tr[now].r==r)return tr[now].c;
    if(tr[now].lazy!=0)update(now);
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(r<=mid)return findmin(lc,l,r);
    else if(mid+1<=l)return findmin(rc,l,r);
    else return min(findmin(lc,l,mid),findmin(rc,mid+1,r));
}
void solve(int x,int y,int k)
{
    int tx=top[x],ty=top[y];
    while(tx!=ty)
    {
        if(dep[tx]>dep[ty])swap(tx,ty),swap(x,y);
        change(1,ys[ty],ys[y],k);
        y=f[ty][0];ty=top[y];
    }
    if(dep[x]>dep[y])swap(x,y);
    change(1,ys[x],ys[y],k);
}
int hehe(int x,int tt)
{
    for(int i=17;i>=0;i--)
    {
        if(tt>=(1<<i))x=f[x][i],tt-=(1<<i);
    }
    return x;
}
int LCA(int x,int y)
{
    if(dep[x]<dep[y])swap(x,y);
    for(int i=17;i>=0;i--)
    {
        if((dep[x]-dep[y])>=(1<<i))x=f[x][i];
    }
    if(x==y)return x;
    for(int i=17;i>=0;i--)
    {
        if(dep[x]>=(1<<i) && f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    }
    return f[x][0];
}
int wy[110000]; 
int main()
{
     int n,m,rt;
     scanf("%d%d",&n,&m);
     for(int i=1;i<n;i++)
     {
        int x,y;
        scanf("%d%d",&x,&y);
        ins(x,y);ins(y,x);
     }
     for(int i=1;i<=n;i++)scanf("%d",&wy[i]);
     scanf("%d",&rt);
     pre_tree_node(rt);pre_tree_edge(rt,rt);bt(1,n);
     for(int i=1;i<=n;i++)change(1,ys[i],ys[i],wy[i]);
     while(m--)
     {
        int opt,x,y,c;
        scanf("%d%d",&opt,&x);
        if(opt==1)rt=x;
        if(opt==3)
        {
            if(rt==x)printf("%d\n",findmin(1,1,n));
            else
            {
                if(LCA(rt,x)==x)
                {
                    int yw=hehe(rt,dep[rt]-dep[x]-1);
                    int ans=findmin(1,1,ys[yw]-1);
                    if(ys[yw]+tot[yw]<=n)ans=min(ans,findmin(1,ys[yw]+tot[yw],n));
                    printf("%d\n",ans);
                }
                else printf("%d\n",findmin(1,ys[x],ys[x]+tot[x]-1));
            }
        }
        if(opt==2)
        {
            scanf("%d%d",&y,&c);
            solve(x,y,c);
        }
     }
     return 0;
}
基于数据挖掘的音乐推荐系统设计与实现 需要一个代码说明,不需要论文 采用python语言,django框架,mysql数据库开发 编程环境:pycharm,mysql8.0 系统分为前台+后台模式开发 网站前台: 用户注册, 登录 搜索音乐,音乐欣赏(可以在线进行播放) 用户登陆时选择相关感兴趣的音乐风格 音乐收藏 音乐推荐算法:(重点) 本课题需要大量用户行为(如播放记录、收藏列表)、音乐特征(如音频特征、歌曲元数据)等数据 (1)根据用户之间相似性或关联性,给一个用户推荐与其相似或有关联的其他用户所感兴趣的音乐; (2)根据音乐之间的相似性或关联性,给一个用户推荐与其感兴趣的音乐相似或有关联的其他音乐。 基于用户的推荐和基于物品的推荐 其中基于用户的推荐是基于用户的相似度找出相似相似用户,然后向目标用户推荐其相似用户喜欢的东西(和你类似的人也喜欢**东西); 而基于物品的推荐是基于物品的相似度找出相似的物品做推荐(喜欢该音乐的人还喜欢了**音乐); 管理员 管理员信息管理 注册用户管理,审核 音乐爬虫(爬虫方式爬取网站音乐数据) 音乐信息管理(上传歌曲MP3,以便前台播放) 音乐收藏管理 用户 用户资料修改 我的音乐收藏 完整前后端源码,部署后可正常运行! 环境说明 开发语言:python后端 python版本:3.7 数据库:mysql 5.7+ 数据库工具:Navicat11+ 开发软件:pycharm
MPU6050是一款广泛应用在无人机、机器人和运动设备中的六轴姿态传感器,它集成了三轴陀螺仪和三轴加速度计。这款传感器能够实时监测并提供设备的角速度和线性加速度数据,对于理解物体的动态运动状态至关重要。在Arduino平台上,通过特定的库文件可以方便地与MPU6050进行通信,获取并解析传感器数据。 `MPU6050.cpp`和`MPU6050.h`是Arduino库的关键组成部分。`MPU6050.h`是头文件,包含了定义传感器接口和函数声明。它定义了类`MPU6050`,该类包含了初始化传感器、读取数据等方法。例如,`begin()`函数用于设置传感器的工作模式和I2C地址,`getAcceleration()`和`getGyroscope()`则分别用于获取加速度和角速度数据。 在Arduino项目中,首先需要包含`MPU6050.h`头文件,然后创建`MPU6050`对象,并调用`begin()`函数初始化传感器。之后,可以通过循环调用`getAcceleration()`和`getGyroscope()`来不断更新传感器读数。为了处理这些原始数据,通常还需要进行校准和滤波,以消除噪声和漂移。 I2C通信协议是MPU6050与Arduino交互的基础,它是一种低引脚数的串行通信协议,允许多个设备共享一对数据线。Arduino板上的Wire库提供了I2C通信的底层支持,使得用户无需深入了解通信细节,就能方便地与MPU6050交互。 MPU6050传感器的数据包括加速度(X、Y、Z轴)和角速度(同样为X、Y、Z轴)。加速度数据可以用来计算物体的静态位置和动态运动,而角速度数据则能反映物体转动的速度。结合这两个数据,可以进一步计算出物体的姿态(如角度和角速度变化)。 在嵌入式开发领域,特别是使用STM32微控制器时,也可以找到类似的库来驱动MPU6050。STM32通常具有更强大的处理能力和更多的GPIO口,可以实现更复杂的控制算法。然而,基本的传感器操作流程和数据处理原理与Arduino平台相似。 在实际应用中,除了基本的传感器读取,还可能涉及到温度补偿、低功耗模式设置、DMP(数字运动处理器)功能的利用等高级特性。DMP可以帮助处理传感器数据,实现更高级的运动估计,减轻主控制器的计算负担。 MPU6050是一个强大的六轴传感器,广泛应用于各种需要实时运动追踪的项目中。通过 Arduino 或 STM32 的库文件,开发者可以轻松地与传感器交互,获取并处理数据,实现各种创新应用。博客和其他开源资源是学习和解决问题的重要途径,通过这些资源,开发者可以获得关于MPU6050的详细信息和实践指南
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值