• [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));
    }
    
  • 相关阅读:
    关于敏捷软件开发的一些感悟
    求出矩阵中,所有元素相加和最大的分块矩阵。
    小组作业提交报告
    结对项目实训——电梯调度
    关于代码测试方面的一些想法和感悟
    用c语言实现文本文件中的字符筛选分析(二)
    用c语言实现文本文件中的字符筛选分析(一)
    4月19日会议(整理——郑云飞)
    4月18日会议总结(整理—祁子梁)
    每日任务看板展示—第一周
  • 原文地址:https://www.cnblogs.com/ZUTTER/p/9855507.html
Copyright © 2020-2023  润新知