线段树合并例题

2023-11-16

https://www.luogu.com.cn/problem/P3224

1. 永无乡

题意:

 给 n 个岛屿,每个岛有一个标号,初始修有 m 条路,有两个操作,操作1 为 给两个岛屿之间修路,操作2为求出 所有能从当前岛屿到达的岛 中标号第k小的岛

思路:

求标号第k小的岛,我们考虑使用权值线段树,通过线段树上二分查找第k小,对于多个岛屿,我们考虑动态开点建 n 棵线段树,对于岛屿修路的操作 使用并查集维护连通块,并利用线段树合并实现岛屿合并

代码:

#include<bits/stdc++.h>
using namespace std;

#define int long long
#define mid ((l+r)>>1)

const int N=1e5+5;
int rt[N],n,m,num,id[N],f[N];
int ls[60*N],rs[60*N],cnt[60*N];

int find(int x){return x==f[x]?x:f[x]=find(f[x]);}

int merge(int x,int y,int l,int r){        //线段树合并
    if(!x)return y;
    if(!y)return x;
    if(l==r){
        cnt[x]+=cnt[y];
        return x;
    }
    ls[x]=merge(ls[x],ls[y],l,mid);
    rs[x]=merge(rs[x],rs[y],mid+1,r);
    cnt[x]=cnt[ls[x]]+cnt[rs[x]];
    return x;
}

void upd(int &p,int l,int r,int x){    //建树
    if(!p)p=++num;
    if(l==r){
        cnt[p]=1;
        return;
    }
    if(x<=mid)upd(ls[p],l,mid,x);
    else upd(rs[p],mid+1,r,x);
    cnt[p]=cnt[ls[p]]+cnt[rs[p]];
}

int q(int p,int l,int r,int k){    //二分查找第k小
    if(cnt[p]<k)return -1;
    if(l==r)return l;
    if(cnt[ls[p]]>=k)return q(ls[p],l,mid,k);
    return q(rs[p],mid+1,r,k-cnt[ls[p]]);
}

void solve(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        id[x]=i;
        upd(rt[i],1,n,x);
        f[i]=i;
    }
    while(m--){
        int u,v;
        cin>>u>>v;
        if(find(u)==find(v))continue;
        u=find(u),v=find(v);
        rt[u]=merge(rt[u],rt[v],1,n);
        f[v]=u;
    }
    cin>>m;
    while(m--){
        string op;
        int x,y;
        cin>>op>>x>>y;
        if(op=="B"){
            if(find(x)==find(y))continue;
            x=find(x),y=find(y);
            rt[x]=merge(rt[x],rt[y],1,n);
            f[y]=x;
        }
        else{
            x=find(x);
            int ans=q(rt[x],1,n,y);
            if(ans!=-1)ans=id[ans];
            cout<<ans<<endl;
        }
    }
    return;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    int T=1;
    //cin>>T;
    while(T--){
        solve();
    }
    return 0;
}


2. 雨天的尾巴

https://www.luogu.com.cn/problem/P4556

题意:

给一棵树型村庄,每次给 x到y路径上的村庄发一袋 z 粮食  ,求最后 每个村庄拥有数量最多的粮食种类

思路:

将树看成有根树,取1作为根,每次发放粮食的操作 利用树上差分转化为4次单点发放粮食,直接修改即可,查询数量最多的粮食种类,我们采用 权值线段树 维护每种粮食的数量,建n棵线段树,最后通过 线段树合并+dfs 求出线段树的树上前缀和

代码:

#include<bits/stdc++.h>
using namespace std;

#define int long long

const int N=1e5+5;
int head[N],cntt=0;        //建图
struct Edge{
    int to,next;
}edge[2*N];
void add(int u,int v){
    edge[++cntt].to=v;
    edge[cntt].next=head[u];
    head[u]=cntt;
}

int f[N][30],dis[N],n,t;
void init(){                //lca
    queue<int>q;
    q.push(1);
    dis[1]=1;
    while(!q.empty()){
        int tmp=q.front();
        q.pop();
        for(int i=head[tmp];i;i=edge[i].next){
            int y=edge[i].to;
            if(dis[y])continue;
            dis[y]=dis[tmp]+1;
            f[y][0]=tmp;
            q.push(y);
            for(int j=1;j<=t;j++){
                f[y][j]=f[f[y][j-1]][j-1];
            }
        }
    }
}
int lca(int u,int v){
    if(dis[u]>dis[v])swap(u,v);
    for(int i=t;i>=0;i--){
        if(dis[f[v][i]]>=dis[u])v=f[v][i];
    }
    if(u==v)return u;
    for(int i=t;i>=0;i--){
        if(f[u][i]!=f[v][i]){
            u=f[u][i],v=f[v][i];
        }
    }
    return f[u][0];
}

#define mid ((l+r)>>1)

int X[N],Y[N],Z[N],rt[N],num=0;
int ls[60*N],rs[60*N],cnt[60*N],pos[60*N];

void pushup(int p){
    if(cnt[ls[p]]>cnt[rs[p]]){
        cnt[p]=cnt[ls[p]];
        pos[p]=pos[ls[p]];
    }
    else if(cnt[rs[p]]>cnt[ls[p]]){
        cnt[p]=cnt[rs[p]];
        pos[p]=pos[rs[p]];
    }
    else{
        cnt[p]=cnt[ls[p]];
        pos[p]=min(pos[ls[p]],pos[rs[p]]);
    }
}

void upd(int &p,int l,int r,int x,int k){
    if(!p)p=++num;
    if(l==r){
        cnt[p]+=k;
        pos[p]=l;
        return;
    }
    if(x<=mid)upd(ls[p],l,mid,x,k);
    else upd(rs[p],mid+1,r,x,k);
    pushup(p);
}

int merge(int x,int y,int l,int r){
    if(!x)return y;
    if(!y)return x;
    if(l==r){
        cnt[x]+=cnt[y];
        pos[x]=l;
        return x;
    }
    ls[x]=merge(ls[x],ls[y],l,mid);
    rs[x]=merge(rs[x],rs[y],mid+1,r);
    pushup(x);
    return x;
}

int ans[N],mx;
void dfs(int x,int ff){
    for(int i=head[x];i;i=edge[i].next){
        int y=edge[i].to;
        if(y==ff)continue;
        dfs(y,x);
        rt[x]=merge(rt[x],rt[y],1,mx);
    }
    if(cnt[rt[x]])ans[x]=pos[rt[x]];
}

void solve(){
    int m;
    cin>>n>>m;
    t=log2(n);
    for(int i=1;i<n;i++){
        int u,v;
        cin>>u>>v;
        add(u,v);
        add(v,u);
    }
    init();
    for(int i=1;i<=m;i++){
        cin>>X[i]>>Y[i]>>Z[i];
        mx=max(mx,Z[i]);
    }
    for(int i=1;i<=m;i++){
        upd(rt[X[i]],1,mx,Z[i],1);
        upd(rt[Y[i]],1,mx,Z[i],1);
        upd(rt[lca(X[i],Y[i])],1,mx,Z[i],-1);
        if(f[lca(X[i],Y[i])][0])
        upd(rt[f[lca(X[i],Y[i])][0]],1,mx,Z[i],-1);
    }
    dfs(1,1);
    for(int i=1;i<=n;i++){
        cout<<ans[i]<<endl;
    }
    return;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int T=1;
    while(T--){
        solve();
    }
    return 0;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

线段树合并例题 的相关文章

随机推荐

  • MTK多国语言相关经验总结

    MTK多国语言相关经验总结 一 移植多国语言移植多国语言主要牵涉到对mmi features h 整个工程的宏控定义文件 fontres c 字体资源文件 的修改 并添加相应的字库文件 1 语言宏控的修改在mmi features h文件中
  • 使用C#语言,基于OpenCvSharp 开发摄像头后台,移动物体位置识别 (一)

    刚刚入门OpenCvSharp 也是小白一枚 教程很少 慢慢摸索 边学边记录 文末附链接 效果 要求 Visual Studio 2017 摄像头x1 准备工作 新建一个 Net Framework 控制台应用 右击解决方案 gt 管理解决
  • 京城游戏人-Day13: 获取被点击的 Button 以及其上的文字内容

    京城游戏人 Day13 获取被点击的 Button 以及其上的文字内容 作者 大锐哥 地址 http blog csdn net prevention 获取被点击的 button var button UnityEngine EventSy
  • Centos + docker,Ubuntu + docker介绍安装及详细使用

    docker笔记 常用命令 设置docker开机自启 sudo chkconfig docker on 查所有镜像 docker images 删除某个镜像 docker rmi CONTAINER ID 容器ID 删除所有镜像 docke
  • Linux命令大全!

    系统信息 arch 显示机器的处理器架构 1 uname m 显示机器的处理器架构 2 uname r 显示正在使用的内核版本 dmidecode q 显示硬件系统部件 SMBIOS DMI hdparm i dev hda 罗列一个磁盘的
  • Grid 布局实现九宫格图片动画

    前言 Grid 布局实现九宫格 background position设置背景图像起始位置 速速来Get吧 文末分享源代码 记得点赞 关注 收藏 1 实现效果 2 实现步骤 定义css变量 九宫格中每个宫格的长 宽为w 宫格之间的间距为ga
  • STL容器的线程安全

    众所周知 STL容器不是线程安全的 对于vector 即使写方 生产者 是单线程写入 但是并发读的时候 由于潜在的内存重新申请和对象复制问题 会导致读方 消费者 的迭代器失效 实际表现也就是招致了core dump 另外一种情况 如果是多个
  • firefox os_如何在电视上测试Firefox OS应用

    firefox os One of my responsibilities in my new role in Partner Engineering at Mozilla is testing HTML5 powered apps and
  • 解决git中出现的“bash syntax error near unexpected token ’(‘”错误

    今天来分享一篇关于我在git使用过程中出现的一个错误 错误信息 bash syntax error near unexpected token 翻译过来就是提示我在 这里有错误 而这个错误是我在使用git commit提交时候产生的 我当时
  • 4. Docker 构建镜像

    Docker 构建镜像 docker制作镜像通常是通过两种方式来实现的 第一种是通过容器的 commit 第二种是通过 Buildfile来实现的 docker commit 打包镜像 容器在运行过程中我们难免会做一些修改 比如运行的mys
  • 程序框架---缩进(Python)

    缩进 类定义 函数定义 选择结构 循环结构 with块 行尾的冒号表示缩进的开始 python程序是依靠代码块的缩进来体现代码之间的逻辑关系的 缩进结束就表示一个代码块结束了 同一级别代码块的缩进量必须相同 一般而言 以4个空格或一个TAB
  • OLED透明屏:在广告领域中的应用,为品牌注入更强的视觉冲击

    OLED透明屏作为一项引人注目的技术创新 其独特的透明度和高清晰度为各行各业带来了全新的展示和创意空间 本文将详细介绍其透明度 高对比度 超薄柔性设计以及强大的颜色表现力 并探讨其在零售 汽车和建筑等领域的应用前景 一 透明度 开启全新的透
  • 聊透spring @Configuration配置类

    本章节我们来探索Spring中一个常用的注解 Configuration 我们先来了解一下该注解的作用是 用来定义当前类为配置类 那啥是配置类啊 有啥用啊 这个我们得结合实际使用场景来说 通常情况下 加了 Configuration的配置类
  • 机器学习——决策树(Decision Trees)

    决策树 决策树是机器学习中一种最为常见的算法 顾名思义 决策树是基于树结构来进行决策的 这恰是人类在面对决策问题时一种很自然的处理机制 决策树的生成算法可以说是信息论的一种应用 但它其实只用到了信息论中的一小部分思想 因此对信息论有个基础性
  • Python系列教程-目录

    转载至 http www cricode com 3086 html Python初级教程 Python快速教程 手册 Python基础01 Hello World Python基础02 基本数据类型 Python基础03 序列 Pytho
  • CSS 之层叠规则(权级、权重、顺序)详解

    文章目录 参考 描述 定义 层叠 层叠与冲突 规则 权重 优先级 权重值的叠加 顺序 权级 权级 层叠规则的运用 顺序 尾声 参考 项目 描述 MDN WEB Docs 优先级 Amily mo 令人烦恼的css选择器权值问题 Amily
  • 《TCP/IP网络编程》--基于TCP实现字符串对话和文件传输

    1 基于TCP实现字符串对话 主要需求 服务器端和客户端各传递 1 次字符串 基于 TCP 协议 传递字符串前先以 4 字节整数型方式传递字符串长度 剩余部分为字符串数据 注 下面的代码基于 Windows 系统实现 1 1 服务器端 gc
  • Java中实现ftp下载文件至本地(详细)

    Java中实现ftp下载文件至本地 详细 欢迎关注蚕豆公众号 不定时分享技术 同时欢迎加入蚕豆技术群哦 扫描公众号点击关于作者加群 2020 09 13 今天记录一下java中实现ftp下载文件至本地的功能模块 同此与大家交流分享有什么不对
  • js每日定时请求接口

    需求是每日十点请求一次接口 初始方法是写一个一分钟的轮询 定时查询系统时间 如果时间为10点就执行请求函数 但是考虑这样太浪费资源 在师傅的帮助下找到了一个更优的方法 计算当前时间和目标时间的时间间隔 如果超过 则设置定时查询的时间间隔为距
  • 线段树合并例题

    https www luogu com cn problem P3224 1 永无乡 题意 给 n 个岛屿 每个岛有一个标号 初始修有 m 条路 有两个操作 操作1 为 给两个岛屿之间修路 操作2为求出 所有能从当前岛屿到达的岛 中标号第k