• bzoj 4552: [Tjoi2016&Heoi2016]排序


    Description

    在2016年,佳媛姐姐喜欢上了数字序列。因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题
    ,需要你来帮助他。这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排
    序分为两种:1:(0,l,r)表示将区间[l,r]的数字升序排序2:(1,l,r)表示将区间[l,r]的数字降序排序最后询问第q
    位置上的数字。

    Input

    输入数据的第一行为两个整数n和m。n表示序列的长度,m表示局部排序的次数。1 <= n, m <= 10^5第二行为n个整
    数,表示1到n的一个全排列。接下来输入m行,每一行有三个整数op, l, r, op为0代表升序排序,op为1代表降序
    排序, l, r 表示排序的区间。最后输入一个整数q,q表示排序完之后询问的位置, 1 <= q <= n。1 <= n <= 10^5
    ,1 <= m <= 10^5
     

    Output

     输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第q位置上的数字。

    Sample Input

    6 3
    1 6 2 5 3 4
    0 1 4
    1 3 6
    0 2 4
    3

    Sample Output

    5

    HINT

    思路

    看过题解后,惊叹!

    这题出的好,我给满分

    它有个特性:是1~n的排列,局部排序只跟数的大小有关。

    所以,有一个特别妙的方法:

    二分答案mid,再检查第q位置上的数是>mid还是<=mid。

    为了检查第q位置上的数经过m次操作后与mid的大小关系,

    我们可以把原序列中>mid的数设为1,<=mid的数设为0。

    这样,每次局部排序,就相当于对一个01数列进行排序,就能用线段树轻松地维护这个序列了。

    最后查询第q位置上的数是1还是0即可。

    非常妙啊

    想不到设0、1的方法就已经滚出了/(ㄒoㄒ)/~~

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 using namespace std;
     4 #define ref(i,x,y)for(int i=x;i<=y;++i)
     5 int read()
     6 {
     7     char c=getchar();int d=0,f=1;
     8     for(;c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
     9     for(;c>='0'&&c<='9';d=d*10+c-48,c=getchar());
    10     return d*f;
    11 }
    12 const int N=100001;
    13 int n,m,pos,s[N];
    14 struct xint{int o,x,y;}q[N];
    15 struct node{int x,y,s,tag;}a[N*10];
    16 void pushdown(int t)
    17 {
    18     if(a[t].tag<0)return;
    19     a[t<<1].tag=a[t].tag;
    20     a[t<<1].s=(a[t<<1].y-a[t<<1].x+1)*a[t].tag;
    21     a[t<<1|1].tag=a[t].tag;
    22     a[t<<1|1].s=(a[t<<1|1].y-a[t<<1|1].x+1)*a[t].tag;
    23     a[t].tag=-1;
    24 }
    25 void pushup(int t)
    26 {
    27     a[t].s=a[t<<1].s+a[t<<1|1].s;
    28 }
    29 void build(int x,int y,int t)
    30 {
    31     a[t].tag=-1;
    32     a[t].x=x;a[t].y=y;
    33     if(x==y)return;
    34     int m=(x+y)>>1;
    35     build(x,m,t<<1);
    36     build(m+1,y,t<<1|1);
    37 }
    38 void modify(int x,int y,int t,int s)
    39 {
    40     if(x<=a[t].x&&a[t].y<=y)
    41     {
    42         a[t].tag=s;
    43         a[t].s=(a[t].y-a[t].x+1)*s;
    44         return;
    45     }
    46     pushdown(t);
    47     int m=(a[t].x+a[t].y)>>1;
    48     if(x<=m)modify(x,y,t<<1,s);
    49     if(m<y)modify(x,y,t<<1|1,s);
    50     pushup(t);
    51 }
    52 int query(int x,int y,int t)
    53 {
    54     if(x<=a[t].x&&a[t].y<=y)return a[t].s;
    55     pushdown(t);
    56     int m=(a[t].x+a[t].y)>>1,res=0;
    57     if(x<=m)res+=query(x,y,t<<1);
    58     if(m<y)res+=query(x,y,t<<1|1);
    59     return res;
    60 }
    61 int check(int x)
    62 {
    63     ref(i,1,n)modify(i,i,1,s[i]>x);
    64     ref(i,1,m)
    65     {
    66         int s=query(q[i].x,q[i].y,1);
    67         if(q[i].o==0)
    68         {
    69             if(q[i].y-s>=q[i].x)
    70                 modify(q[i].x,q[i].y-s,1,0);
    71             if(s)modify(q[i].y-s+1,q[i].y,1,1);
    72         }
    73         if(q[i].o==1)
    74         {
    75             if(s)modify(q[i].x,q[i].x+s-1,1,1);
    76             if(q[i].y>=q[i].x+s)
    77                 modify(q[i].x+s,q[i].y,1,0);
    78         }
    79     }
    80     return query(pos,pos,1);
    81 }
    82 int main()
    83 {
    84     n=read(),m=read();
    85     ref(i,1,n)s[i]=read();
    86     ref(i,1,m)q[i].o=read(),q[i].x=read(),q[i].y=read();
    87     pos=read();
    88     build(1,n,1);
    89     int l=1,r=n;
    90     while(l<r)
    91     {
    92         int m=(l+r)>>1;
    93         if(check(m))l=m+1;else r=m;
    94     }
    95     cout<<l<<endl;
    96 }
  • 相关阅读:
    STM32时钟树
    js jQuery函数 $.ajax()
    jQuery 语法
    jQuery介绍
    python笔记2 生成器 文件读写
    python笔记1,语法,函数,类和实例,异常
    Scrapy爬虫入门系列4抓取豆瓣Top250电影数据
    Scrapy爬虫入门系列3 将抓取到的数据存入数据库与验证数据有效性
    opus 规范 与参数解析
    开源播放器ijkplayer源码结构
  • 原文地址:https://www.cnblogs.com/Blog-of-Eden/p/6675520.html
Copyright © 2020-2023  润新知