数据结构训练之四

https://www.luogu.org/problem/P2824#submit

做法:

由于将一个普通序列排序很慢,需要nlogn的时间,所以我们试着把它转化为对01序列排序。先来考虑一个简单的问题:


  • 如何将一个01序列排序?(logn的复杂度)
  • 对于这个问题,我们使用线段树来维护。查询一段区间内的1的个数记为cnt1,如果是升序,就将这段区间的[r-cnt1+1, r]都更改为1,将[l, r-cnt1]更改为0。降序则将[l, l+cnt1-1]更改为1,将[l+cnt, r]更改为0。这样我们就成功地把排序转化为了区间查询和区间修改。


接下来我们来说本题的做法:

这是一个离线的做法。首先二分答案mid。我们把原排列中大于等于mid的数都标记为1,小于mid的都标记为0。然后对于每个操作我们就将01序列排个序。最后如果第p个位子仍是1的话就是可行的。

这个二分成立因为是满足单调性的:可以简单地假设一下,如果你二分的答案是1,那么原序列所有的值都转化为了1,所以最后肯定是true。如果二分一个值成立当且仅当这个位子的值大于等于mid,故如果check返回true,则l = mid+1,否则r = mid-1。

(这题的思想可以借鉴,比较巧妙)

code by wzxbeliever:

#include<bits/stdc++.h>
#define ll long long
#define il inline
#define ri register int
#define lowbit(x) x&(-x)
using namespace std;
const int maxn=1e5+5;
int n,m,id,ans,mm;
int val[maxn],tree[maxn<<2],tag[maxn<<2];
struct node{
    int op,LL,RR;
}Q[maxn];
il void up(int rt){tree[rt]=tree[rt<<1]+tree[rt<<1|1];return;}
il void bulid(int l,int r,int rt){
    if(l==r){tree[rt]=val[l]>=mm;tag[rt]=0;return;}
    int mid=l+r>>1;
    bulid(l,mid,rt<<1);
    bulid(mid+1,r,rt<<1|1);
    up(rt);tag[rt]=0;//多次记得每次清空 0---->什么也不干 ;1----->赋值为1;2----->赋值为0
    return;
}
il void modify(int l,int r,int rt,int p){
    if(!p)return;tag[rt]=p;
    if(p==1)tree[rt]=r-l+1;
    else tree[rt]=0;
}
il void down(int l,int r,int rt){
    if(!tag[rt])return;
    int mid=l+r>>1;
    modify(l,mid,rt<<1,tag[rt]);
    modify(mid+1,r,rt<<1|1,tag[rt]);
    tag[rt]=0;
}
il int query(int l,int r,int rt,int L,int R){
    if(L<=l&&r<=R)return tree[rt];
    int mid=l+r>>1;
    int tot=0;
    down(l,r,rt);
    if(L<=mid)tot+=query(l,mid,rt<<1,L,R);
    if(mid<R)tot+=query(mid+1,r,rt<<1|1,L,R);
    return tot;
}
il void upd(int l,int r,int rt,int L,int R,int p){
    if(L<=l&&r<=R){modify(l,r,rt,p);return;}
    int mid=l+r>>1;
    down(l,r,rt);
    if(mid>=L)upd(l,mid,rt<<1,L,R,p);
    if(mid<R)upd(mid+1,r,rt<<1|1,L,R,p);
    up(rt);
}
il int querypoint(int l,int r,int rt,int pos){
    if(l==r)return tree[rt];
    int mid=l+r>>1;
    down(l,r,rt);
    if(pos<=mid)return querypoint(l,mid,rt<<1,pos);
    else return querypoint(mid+1,r,rt<<1|1,pos);
}
il bool check(){
    bulid(1,n,1);
    for(ri i=1;i<=m;i++){
        int L=Q[i].LL,R=Q[i].RR;
        int cnt=query(1,n,1,L,R);
        if(cnt==0)continue;//这个句子很关键,不然会越界re4个点
        if(Q[i].op==0){
            upd(1,n,1,L,R-cnt,2);
            upd(1,n,1,R-cnt+1,R,1);
        }
        else {
            upd(1,n,1,L,L+cnt-1,1);
            upd(1,n,1,L+cnt,R,2);
        }
    }
    if(querypoint(1,n,1,id)==1)return true;
    else return false;
}
int main(){
    scanf("%d%d",&n,&m);
    for(ri i=1;i<=n;i++)scanf("%d",&val[i]);
    for(ri i=1;i<=m;i++)scanf("%d%d%d",&Q[i].op,&Q[i].LL,&Q[i].RR);
    scanf("%d",&id);
    int l=1,r=n;
    while(l<=r){
        mm=l+r>>1;
        if(check())ans=mm,l=mm+1;
        else r=mm-1;
    }
    printf("%d\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/wzxbeliever/p/11748618.html

时间: 2024-10-11 02:06:56

数据结构训练之四的相关文章

42. 蛤蟆的数据结构笔记之四十二图的遍历之广度优先

42. 蛤蟆的数据结构笔记之四十二图的遍历之广度优先 本篇名言:"生活真象这杯浓酒 ,不经三番五次的提炼呵 , 就不会这样一来可口 ! -- 郭小川" 继续看下广度优先的遍历,上篇我们看了深度遍历是每次一个节点的链表是走到底的. 欢迎转载,转载请标明出处:http://write.blog.csdn.net/postedit/47029275 1.  原理 首先,从图的某个顶点v0出发,访问了v0之后,依次访问与v0相邻的未被访问的顶点,然后分别从这些顶点出发,广度优先遍历,直至所有的

48. 蛤蟆的数据结构笔记之四十八的有向无环图的应用关键路径

48. 蛤蟆的数据结构笔记之四十八的有向无环图的应用关键路径 本篇名言:"富贵不淫贫贱乐 ,男儿到此是豪雄.-- 程颢" 这次来看下有向无环图的另一个应用关键路径. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47135061 1.  关键路径 与AOV-网相对应的是AOE-网(Activity On Edge)即边表示活动的网.AOE-网是一个带权的有向无环图,其中,顶点表示事件(Event),弧表示活动,权表

49. 蛤蟆的数据结构笔记之四十九图的连通性问题

49. 蛤蟆的数据结构笔记之四十九图的连通性问题 本篇名言:"我们不得不饮食.睡眠.游惰.恋爱,也就是说,我们不得不接触生活中最甜蜜的事情:不过我们必须不屈服于这些事物 .....--约里奥?居里"     此篇就作为数据结构入门笔记的最后一篇吧. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47135259 设图G=(V,E)是一个无向图,G的一个连通分支是一个最大的连通子图,即一个连通分支是不包含在任何更大的

46. 蛤蟆的数据结构笔记之四十六普里姆算法

46. 蛤蟆的数据结构笔记之四十六普里姆算法 本篇名言:"手莫伸 ,伸手必被捉.党与人民在监督 ,万目睽睽难逃脱.汝言惧捉手不伸 ,他道不伸能自觉 , 其实想伸不敢伸 ,人民咫尺手自缩.-- 陈毅" 连通图的生成树是一个极小的连通子图,它含有图中全部的顶点,但只有足以构成一棵树的n-1条边.所谓的最小成本,就是n个顶点,用n-1条边把一个连通图连接起来,并且使得权值的和最小.构造连通网的最小代价生成树,即最小生成树(Minimum Cost Spanning Tree). 找连通图的最

44. 蛤蟆的数据结构笔记之四十四弗洛伊德Floyd算法

44. 蛤蟆的数据结构笔记之四十四弗洛伊德Floyd算法 本篇名言:"希望是厄运的忠实的姐妹. --普希金" 我们继续来看下数据结构图中的一个算法,这个算法来自图灵奖得主. 1.  Floyd算法介绍 Floyd算法又称为插点法,是一种用于寻找给定的加权图中多源点之间最短路径的算法.该算法名称以创始人之一.1978年图灵奖获得者.斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名.注意这个可不是心理学的那个弗洛伊德. 是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径

41 蛤蟆的数据结构笔记之四十一图的遍历之深度优先

41  蛤蟆的数据结构笔记之四十一图的遍历之深度优先 本篇名言:"对于我来说 , 生命的意义在于设身处地替人着想 , 忧他人之忧 , 乐他人之乐. -- 爱因斯坦" 上篇我们实现了图的邻接多重表表示图,以及深度遍历和广度遍历的代码,这次我们先来看下图的深度遍历. 欢迎转载,转载请标明出处: 1.  原理 图遍历又称图的遍历,属于数据结构中的内容.指的是从图中的任一顶点出发,对图中的所有顶点访问一次且只访问一次.图的遍历操作和树的遍历操作功能相似.图的遍历是图的一种基本操作,图的许多其它

47. 蛤蟆的数据结构笔记之四十七的有向无环图的应用排序

47.蛤蟆的数据结构笔记之四十七的有向无环图的应用排序 本篇名言:"君子喻于义 ,小人喻于利. -- 孔丘" 接下去来看下有向无环图. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47110397 1.  有向无环图 一个无环的有向图称做有向无环图(directedacycline praph).简称DAG图.DAG 图是一类较有向树更一般的特殊有向图,图1给出了有向树.DAG图和有向图 有向无环图是描述含有公共

43. 蛤蟆的数据结构笔记之四十三最短路径之迪杰斯特拉(Dijkstra )算法

43. 蛤蟆的数据结构笔记之四十三最短路径之迪杰斯特拉(Dijkstra )算法 本篇名言:"辛勤的蜜蜂永没有时间悲哀.--布莱克" 这次来看下Dijkstra )算法.还是老方法,先原理,后实现.代码来自网络. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47046031 1.  最短路径 最短路径问题是图论研究中的一个经典算法问题, 旨在寻找图(由结点和路径组成的)中两结点之间的最短路径. 管道铺设.线路安排

4、蛤蟆的数据结构笔记之四栈和队列定义

4.蛤蟆的数据结构笔记之四栈和队列定义 本篇名言:"人生应该如蜡烛一样,从顶燃到底,一直都是光明的." 今天学习栈和队列了.从第二篇学习时候我们知道,其实也是线性表的一种. 我们先来看下定义. 欢迎转载,转载请标明出处: 1.  栈 栈(stack)又名堆栈,它是一种运算受限的线性表.其限制是仅允许在表的一端进行插入和删除运算.这一端被称为栈顶,相对地,把另一端称为栈底.向一个栈插入新元素又称作进栈.入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素:从一个栈删除元素又称