[HEOI2016/TJOI2016]排序

4552: [Tjoi2016&Heoi2016]排序

Time Limit: 60 Sec Memory Limit: 256 MB

Submit: 2366 Solved: 1188

[Submit][Status][Discuss]

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

Source

[Submit][Status][Discuss]



二分+线段树

两个log ==

然后就随便做啦


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define update(now) d[now]=d[now*2]+d[now*2+1]
#define LL long long
#define M 400001
#define max(a,b) ((a)>(b)? (a):(b))
#define min(a,b) ((a)<(b)? (a):(b))

using namespace std;

int i,m,n,h,j,k,d[M],a[M], s[M][3],q,maxx,b[M],lazy[M];

void down(int now,int l,int r)
{
    if(!b[now]) return ;
    int mid=(l+r)>>1;
    d[now*2]=lazy[now]*(mid-l+1);
    d[now*2+1]=lazy[now]*(r-mid);
    lazy[now*2]=lazy[now*2+1]=lazy[now];
    b[now*2]=b[now*2+1]=1;
    b[now]=lazy[now]=0;
}

void built(int now,int l,int r,int z)
{
    if(l==r)
    {
        if(a[l]>=z) d[now]=1;
        else d[now]=0;
        lazy[now]=b[now]=0;
        return;
    }
    int mid=(l+r)>>1;
    built(now*2,l,mid,z);
    built(now*2+1,mid+1,r,z);
    update(now);
}

void modify(int now,int l,int r,int ll,int rr,int z)
{
    if(l>=ll && r<=rr)
    {
        d[now]=(r-l+1)*z;
        lazy[now]=z;
        b[now]=1;
        return ;
    }
    down(now,l,r);
    int mid=(l+r)>>1;
    if(ll<=mid) modify(now*2,l,mid,ll,rr,z);
    if(rr>mid) modify(now*2+1,mid+1,r,ll,rr,z);
    update(now);
}

int find1(int now,int l,int r,int ll,int rr)
{
    if(l>=ll && r<=rr) return d[now];
    int mid=(l+r)>>1,ans=0;
    down(now,l,r);
    if(ll<=mid) ans+=find1(now*2,l,mid,ll,rr);
    if(rr>mid) ans+=find1(now*2+1,mid+1,r,ll,rr);
    return ans;
}

int find(int now,int l,int r,int w)
{
    if(l==r) return d[now];
    int mid=(l+r)>>1;
    down(now,l,r);
    if(w<=mid) return find(now*2,l,mid,w);
    return find(now*2+1,mid+1,r,w);
}

bool check(int now)
{
    for(int i=1;i<=m;i++)
    {
        int t=find1(1,1,n,s[i][1],s[i][2]);
        if(!t) continue;
        if(s[i][0])
        {
            modify(1,1,n,s[i][1]+t,s[i][2],0);
            modify(1,1,n,s[i][1],s[i][1]+t-1,1);
        }
        else
        {
            modify(1,1,n,s[i][2]-t+1,s[i][2],1);
            modify(1,1,n,s[i][1],s[i][2]-t,0);
        }
    }
    return find(1,1,n,q);
}

int ef(int l,int r)
{
    int mid=l,tmp=l;
    while(r>=l)
    {
        mid=(l+r)>>1;
        memset(b,0,sizeof(b));
        memset(d,0,sizeof(d));
        memset(lazy,0,sizeof(lazy));
        built(1,1,n,mid);
        if(check(mid)) tmp=mid, l=mid+1;
        else r=mid-1;
    }
    return tmp;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++) scanf("%d",&a[i]);
    for(i=1;i<=m;i++) scanf("%d%d%d",&s[i][0],&s[i][1],&s[i][2]);
    scanf("%d",&q);
    printf("%d",ef(0,n));
}

原文地址:https://www.cnblogs.com/ZUTTER/p/9855507.html

时间: 2024-11-06 19:48:22

[HEOI2016/TJOI2016]排序的相关文章

[HEOI2016/TJOI2016]排序 解题报告

[HEOI2016/TJOI2016]排序 题意 给出一个大小为 \(n\) 的排列, 对这个排列进行 \(m\) 次操作, 操作分为以下两种, 0 l r 表示将区间 \([l,r]\) 的数升序排序. 1 l r 表示将区间 \([l,r]\) 的数降序排序. 询问 \(m\) 次操作后下标为 \(q\) 的数字. 思路 不看题解打死也想不出来系列 考虑二分答案. 设当前二分的答案为 \(mid\), 把原排列中 大于等于 \(mid\) 的数标记为 \(1\), 小于 \(mid\) 的数

[HEOI2016&amp;TJOI2016] 排序(线段树)

4552: [Tjoi2016&Heoi2016]排序 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 2703  Solved: 1386[Submit][Status][Discuss] Description 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题 ,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排 序分为两种:1:(0,l,

[Luogu2824] [HEOI2016/TJOI2016]排序

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

LGP2824【[HEOI2016/TJOI2016]排序】

一道神题ORZ,思路真的很妙啊. ### 正文部分: 题意: 给一个序列,可以对某一个区间升序和降序排序,问你最后数列中第$Q$个数是什么? 乍一看貌似毫无思路,于是我们考虑一个更简单的问题:如果对$1$个$01$序列执行上面的操作,是不是就可以变得简单一点? 设某段区间$[l,r]$里总共有$cnt$个1 那么降序排就是把$l\sim l+cnt - 1$修改为$1$,把$l+cnt \sim r$修改为$0$ 升序排则是把$r-cnt+1\sim r$修改为$1$,$l\sim r-cnt$

【线段树合并】【P2824】 [HEOI2016/TJOI2016]排序

Description 给定一个长度为 \(n\) 的排列,有 \(m\) 次操作,每次选取一段局部进行升序或降序排序,问你一波操作后某个位置上的数字是几 Hint \(1~\leq~n,~m~\leq~10^5\) Solution 有两种做法,一种在线一种离线,这里把在线部分讲得更清楚点吧-- 考虑离线算法,我们二分该位置上的答案,将大于该数的元素置为 \(1\),小于该数的元素置为 \(0\),然后模拟所有的排序并检验.由于使用线段树对 \(0/1\) 序列多次局部排序可以做到 \(O(m

luogu_P2824 [HEOI2016/TJOI2016]排序

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

Luogu P2824 [HEOI2016/TJOI2016]排序

Link 先二分答案,这样所有的数字就都变成了\(0,1\). 那么区间排序就相当于区间求和再区间覆盖了. #include<bits/stdc++.h> using namespace std; #define N 100007 int read(){int x=0,c=getchar();while(!isdigit(c))c=getchar();while(isdigit(c))x=x*10+c-48,c=getchar();return x;} int a[N],sum[N<&l

[LuoguP4094] [HEOI2016] [TJOI2016]字符串(二分答案+后缀数组+ST表+主席树)

[LuoguP4094] [HEOI2016] [TJOI2016]字符串(二分答案+后缀数组+ST表+主席树) 题面 给出一个长度为\(n\)的字符串\(s\),以及\(m\)组询问.每个询问是一个四元组\((a,b,c,d)\),问\(s[a,b]\)的所有子串和字符串\(s[c,d]\)的最长公共前缀长度的最大值. \(n,m \leq 10^5\) 分析 显然答案有单调性.首先我们二分答案\(mid\),考虑如何判定. 如果mid这个答案可行,那么一定存在一个后缀x,它的开头在\([a,

bzoj4552【TJOI2016&amp;HEOI2016】排序

4552: [Tjoi2016&Heoi2016]排序 Time Limit: 60 Sec  Memory Limit: 256 MB Submit: 291  Solved: 171 [Submit][Status][Discuss] Description 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题 ,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排 序分为两种:1:(0,l,