歌名 - 歌手
0:00

    【bzoj4552】【Tjoi2016&Heoi2016】【NOIP2016模拟7.12】排序

    题目

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

    分析

    二分答案,
    把二分出的ans与原序列比较,小于ans的数改为-1,大于ans的数改为1。
    对于输入的每一个修改,用线段树来处理。
    最后求出\(q\)位上的数是-1还是1,然后接着二分。

    #include <cmath>
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    const int maxlongint=2147483647;
    const int mo=1000000007;
    const int N=100005;
    using namespace std;
    int a[N],n,m,re[N][4],k,ans,lazy[N*5],_0[N*5],_1[N*5];
    int down(int v,int mid,int l,int r)
    {
    	if(lazy[v]==-1)
    	{
    		lazy[v*2+1]=lazy[v*2]=lazy[v];
    		_0[v*2]=mid-l+1;
    		_0[v*2+1]=r-(mid+1)+1;
    		_1[v*2]=0;
    		_1[v*2+1]=0;
    	}
    	if(lazy[v]==1)
    	{
    		lazy[v*2+1]=lazy[v*2]=lazy[v];
    		_1[v*2]=mid-l+1;
    		_1[v*2+1]=r-(mid+1)+1;
    		_0[v*2]=0;
    		_0[v*2+1]=0;
    	}
    	lazy[v]=0;
    }
    int put(int v,int l,int r,int x,int y)
    {
    	if(l==r)
    	{
    		if(y==-1)
    			_0[v]=1;
    				else _1[v]=1;
    		return 0;
    	}
    	int mid=(l+r)/2;
    	if(x<=mid)
    		put(v*2,l,mid,x,y);
    	else
    		put(v*2+1,mid+1,r,x,y);
    	_0[v]=_0[v*2]+_0[v*2+1];
    	_1[v]=_1[v*2]+_1[v*2+1];
    }
    int get(int v,int l,int r,int x,int y)
    {
    	if(l==x && r==y)
    	{
    		return _1[v];
    	}
    	int mid=(l+r)/2;
    	down(v,mid,l,r);
    	int o;
    	if(y<=mid)
    		o=get(v*2,l,mid,x,y);
    	else
    	if(x>mid)
    		o=get(v*2+1,mid+1,r,x,y);
    	else
    		o=get(v*2,l,mid,x,mid)+get(v*2+1,mid+1,r,mid+1,y);
    	_0[v]=_0[v*2]+_0[v*2+1];
    	_1[v]=_1[v*2]+_1[v*2+1];
    	return o;
    }
    int change(int v,int l,int r,int x,int y,int value)
    {
    	if(y<x) return 0;
    	int mid=(l+r)/2;
    	if(l==x && r==y)
    	{
    		lazy[v]=value;
    		if(value<0)
    		{
    			_0[v]=r-l+1;
    			_1[v]=0;
    		}
    		else
    		{
    			_1[v]=r-l+1;
    			_0[v]=0;	
    		}
    		return 0;
    	}
    	down(v,mid,l,r);
    	if(y<=mid)
    		change(v*2,l,mid,x,y,value);
    	else
    	if(x>mid)
    		change(v*2+1,mid+1,r,x,y,value);
    	else
    		change(v*2,l,mid,x,mid,value),change(v*2+1,mid+1,r,mid+1,y,value);
    	_0[v]=_0[v*2]+_0[v*2+1];
    	_1[v]=_1[v*2]+_1[v*2+1];
    }
    int find(int v,int l,int r,int x)
    {
    	if(l==r)
    	{
    		return _0[v];
    	}
    	int mid=(l+r)/2;
    	down(v,mid,l,r);
    	int o;
    	if(x<=mid)
    		o=find(v*2,l,mid,x);
    	else
    		o=find(v*2+1,mid+1,r,x);
    	_0[v]=_0[v*2]+_0[v*2+1];
    	_1[v]=_1[v*2]+_1[v*2+1];
    	return o;
    }
    bool check(int x)
    {
    	memset(lazy,0,sizeof(lazy));
    	memset(_0,0,sizeof(_0));
    	memset(_1,0,sizeof(_1));
    	for(int i=1;i<=n;i++)
    	{
    		int g=a[i]<=x?-1:1;
    		put(1,1,n,i,g);
    	}
    	for(int i=1;i<=m;i++)
    	{
    		int p1=get(1,1,n,re[i][2],re[i][3]);
    		if(!re[i][1])
    		{
    			change(1,1,n,re[i][2],re[i][3]-p1,-1);
    			change(1,1,n,re[i][3]-p1+1,re[i][3],1);
    		}
    		else
    		{
    			change(1,1,n,re[i][2],re[i][2]+p1-1,1);
    			change(1,1,n,re[i][2]+p1,re[i][3],-1);	
    		}
    	}
    	if(find(1,1,n,k))
    		return true;
    			else return false;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    	}
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%d%d%d",&re[i][1],&re[i][2],&re[i][3]);
    	}
    	scanf("%d",&k);
    	int l=1,r=n;
    	while(l<r)
    	{
    		int mid=(l+r)/2;
    		if(check(mid))
    		{
    			r=mid;
    		}
    		else
    		{
    			l=mid+1;
    		}
    	}
    	printf("%d",l);
    }
    
    posted @ 2018-05-09 12:31  无尽的蓝黄  阅读(131)  评论(0编辑  收藏  举报