首页 > 其他分享 > [蓝桥杯 2021 省 B] 双向排序 (线段树)

[蓝桥杯 2021 省 B] 双向排序 (线段树)

时间:2023-08-13 13:44:17浏览次数:40  
标签:int sum tr 节点 蓝桥 add num 2021 线段

调了整整5个小时,结果发现自己建树的方式有误,气死我了气死我了,比较好的一道线段树(虽然我不会-----

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n,m,res,point;
vector<int>v[2]; // 用于存储结果的数组,下标0表示sum为0,下标1表示sum为1

struct node
{
    int l,r,sum,add; // l表示左端点,r表示右端点,sum表示[l, r]区间内sum的个数,add表示懒惰标记
}tr[N*2]; // 线段树的节点数组

void pushup(int u)
{
    tr[u].sum=tr[2*u].sum+tr[2*u+1].sum; // 合并子节点的sum值更新父节点的sum值
}

void pushdown(int u)
{
    if(tr[u].add==-1) return; // 如果没有懒惰标记,直接返回
    auto &root=tr[u],&left=tr[2*u],&right=tr[2*u+1]; // 引用父节点、左子节点、右子节点
    left.add=root.add,left.sum=(left.r-left.l+1)*root.add; // 更新左子节点的懒惰标记和sum值
    right.add=root.add,right.sum=(right.r-right.l+1)*root.add; // 更新右子节点的懒惰标记和sum值
    root.add=-1; // 清除父节点的懒惰标记
}

void build(int u,int l,int r)
{
    if(l==r) tr[u]={l,r,1,-1}; // 叶节点初始化,sum为1,懒惰标记为-1
    else{
        tr[u]={l,r}; // 非叶节点初始化
        int mid=(l+r)>>1;
        build(2*u,l,mid); // 递归构建左子树
        build(2*u+1,mid+1,r); // 递归构建右子树
        pushup(u); // 合并子节点的信息更新父节点
    }
}

void modify1(int u,int val)
{
    int num=tr[u].r-tr[u].l+1-tr[u].sum; // 当前节点区间内0的个数
    if(num<=val){
        tr[u].sum=tr[u].r-tr[u].l+1;
        tr[u].add=1; // 更新懒惰标记为1,表示当前区间内的sum全部变为1
        return;
    }
    pushdown(u); // 将当前节点的懒惰标记下传到子节点
    auto &left=tr[2*u],&right=tr[2*u+1];
    int l_num=left.r-left.l+1-left.sum; // 左子节点区间内0的个数
    int r_num=right.r-right.l+1-right.sum; // 右子节点区间内0的个数
    if(l_num>=val) modify1(2*u,val); // 如果左子节点区间内的0个数足够,递归更新左子节点
    else modify1(2*u,l_num),modify1(2*u+1,val-l_num); // 否则分别更新左右子节点
    pushup(u); // 更新当前节点的信息
}

void modify0(int u,int val)
{
    int num=tr[u].sum; // 当前节点区间内1的个数
    if(val>=num){
        tr[u].sum=0,tr[u].add=0; // 更新当前节点的sum为0,懒惰标记为0
        return;
    }
    pushdown(u); // 将当前节点的懒惰标记下传到子节点
    auto &left=tr[2*u],&right=tr[2*u+1];
    int l_num=left.sum; // 左子节点区间内1的个数
    int r_num=right.sum; // 右子节点区间内1的个数
    if(l_num>=val) modify0(2*u,val); // 如果左子节点区间内的1个数足够,递归更新左子节点
    else modify0(2*u,l_num),modify0(2*u+1,val-l_num); // 否则分别更新左右子节点
    pushup(u); // 更新当前节点的信息
}

int query(int u,int pos)
{
    if(tr[u].l==tr[u].r) return tr[u].sum; // 叶节点直接返回sum值
    pushdown(u); // 将当前节点的懒惰标记下传到子节点
    int mid=tr[u].l+tr[u].r>>1;
    if(pos<=mid) return query(2*u,pos); // 根据位置递归查询左子树或右子树
    else return query(2*u+1,pos);
}

int main()
{
    cin>>n>>m;
    build(1,1,n); // 构建线段树
    point=1;
    while(m--){
        int op,x;
        cin>>op>>x;
        if(op==1){
            if(point<=x) continue;
            modify1(1,point-x); // 将前面的0变为1
            point=x;
        }
        else{
            if(point>x) continue;
            modify0(1,x-point+1); // 将后面的1变为0
            point=x+1;
        }
    }
    for(int i=1;i<=n;i++){
        if(query(1,i)==0) v[0].push_back(i); // 根据sum值判断属于哪个分组
        else v[1].push_back(i);
    }
    for(int i=v[0].size()-1;i>=0;i--) cout<<v[0][i]<<" "; // 输出结果
    for(int i=0;i<v[1].size();i++) cout<<v[1][i]<<" ";
    return 0;
}

 

标签:int,sum,tr,节点,蓝桥,add,num,2021,线段
From: https://www.cnblogs.com/o-Sakurajimamai-o/p/17626484.html

相关文章

  • CorelCAD中文版下载-CorelCAD 2021(CAD设计工具) 官方版特色
    CorelCAD是一款CAD软件,可以帮助用户设计和绘制2D和3D图形。它提供了许多功能和工具,包括绘图、编辑、注释、测量和布局等。CorelCAD支持多种文件格式,包括DWG、DXF、DWF和PDF等,可以与其他CAD软件进行互操作。此外,CorelCAD还提供了一些高级功能,例如3D建模、渲染、动画和脚本等,可帮助用......
  • 「题解注释」P7518 [省选联考 2021 A/B 卷] 宝石
    联合省选2021宝石题解-hezlik的博客-洛谷博客(luogu.com.cn)耗时:一晚上+半个上午代码注释:#include<bits/stdc++.h>usingnamespacestd;constintN=500000,C=21;intRi(){intx=0,y=1;charc=getchar();for(;c<'0'||c>'9';c=getchar())if......
  • 武家坡2021 可怜你守在寒窑,可怜你孤孤单单。 苦等我薛男平贵,整整一十八年。
    武家坡2021歌词是:三姐,千错万错,乃是为夫一人之错。你你你你你你,你就宽恕了罢。啊~我的妻,王氏宝钏。可怜你守在寒窑,可怜你孤孤单单。苦等我薛男平贵,整整一十八年。啊~我的妻,王氏宝钏。我不该心起疑窦,我不该口吐轻言。落得个忘恩负义,宛如欺了天。待我将这一十八载,从头说一番......
  • 线段相交Ⅲ
    描述 线段相交有两种情形:一种是“规范相交”,另一种是“非规范相交”。规范相交是指两条线段恰有唯一一个不是端点的公共点。即如果一条线段的端点在另一条线段上则不视为相交。如果两条线段有部分重合,也不视为相交。而非规范相交则把以上两种情况都视为相交。如下图所示:规范......
  • 「学习笔记」线段树优化建图
    在建图连边的过程中,我们时常会碰到这种题目,一个点向一段连续的区间中的点连边或者一个连续的区间向一个点连边,如果我们真的一条一条连过去,那一旦点的数量多了复杂度就爆炸了,这里就需要用线段树的区间性质来优化我们的建图了。那棵线段树大概长这个样子。到时候加边的时候是这个......
  • Nero2021中文版下载|Nero2021中文版 官方版特色
    Nero10官网版是来自德国的著名的光盘刻录软件,Nero10官网版下载后,可以充分利用以下特性刻录自己的光盘。更快捷地利用遥控功能获取到数码媒体上的文件,整合电视,DVD,图像和声音内容,高级搜索功能,LightScribe支持DVD-R多层和DVD+R双层支持更简便的安装和用户界面。欢迎有需要的小伙......
  • 【蓝桥杯备赛系列 | 简单题】数组排序(八大排序演示)
    ......
  • 洛谷 P7739 - [NOI2021] 密码箱
    感觉难度和今年D2T2差不多。首先一个很显然的事情是,每一步得到的分数的分子分母都是互质的,证明参考SBT。而最后答案要求我们将分子分母都求出来而不是求分数值,所以可以很明显的想到将分数当成一个二元组然后维护变换。考虑从右往左扫,假设当前分数为\(\dfrac{x}{y}\),那么扫过......
  • 线段树
    线段树线段树是一种二叉树形数据结构,用于解决区间查询和区间修改问题。它将一个数组划分为若干个连续的区间,每个区间对应线段树的一个节点。通过递归地构建线段树,我们可以在O(logn)的时间复杂度内完成区间查询和区间修改操作。原理线段树的构建过程如下:将原数组划分为n个子......
  • 在不完全重合的情况下,判断线经过另一线段的方法
    importlogginglogging.basicConfig(level=logging.INFO,format='%(asctime)s-%(filename)s[line:%(lineno)d]-%(levelname)s:%(message)s',datefmt='%Y-%m-%d%H:%M:%S')importnumpyasnpfromshapely.......