zoukankan      html  css  js  c++  java
  • bzoj 4552: [Tjoi2016&Heoi2016]排序

    ODT&二分

    看到没有人写关于ODT的题解,所以我决定来一发ODT题解。

    首先这道题的的整体思路就是二分,关于二分的正确性可以感性的理解一下:我们每一次二分一个答案,然后将(<mid)的值变为1,(geq mid)的变为0,每一次只用对0/1序列进行操作,倘若最后我们询问的位置上为0,说明这个位置上的值(< mid),否则就(geq mid),所以它就具有可二分性。

    让我们看看对0/1序列的操作,每次排序就相当于整体的0/1序列排序,也就是区间推平操作,所以我们就珂以用幸福的ODT来做这道题啦.我们每一次只用询问一下这个区间里一共有多少个1,然后将(l)(l+len-1)推平就好辣。当然这需要开O2(否则就死掉了),实测开了O2后跑的快的飞起。

    最后献上我丑陋的代码

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<set>
    #define IT set<node>::iterator
    using namespace std;
    int n,m,opt,k,ll,rr,ans;
    int a[100010];
    int l[100010],r[100010];
    int pan[100010];
    
    int read()
    {
    	int s=0,w=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
    	return s*w;
    }
    
    
    
    struct node
    {
    	int l,r;
    	mutable int val;
    	node(int L,int R=-1,int V=0):l(L),r(R),val(V){}
    	friend bool operator <(const node &a,const node &b)
    	{
    		return a.l<b.l;
    	}
    };
    
    set<node>s;
    
    
    
    IT split(int pos)
    {
    	IT it=s.lower_bound(node(pos));
    	if(it!=s.end()&&it->l==pos)return it;
    	--it;
    	int L=it->l,R=it->r;
    	int V=it->val;
    	s.erase(it);
    	s.insert(node{L,pos-1,V});
    	return s.insert(node{pos,R,V}).first;
    }
    
    int sum(int l,int r)
    {
    	IT it2=split(r+1),it1=split(l);
    	int res=0;
    	for(;it1!=it2;++it1)
    	if(it1->val)res+=(it1->r-it1->l+1);
    	return res;
    }
    
    
    void tuiping(int l,int r,int v)
    {
    	IT it2=split(r+1),it1=split(l);
    	s.erase(it1,it2);
    	s.insert(node{l,r,v});
    }
    
    int check(int x)
    {
    	s.clear();
    	int val=(a[1]>=x),len=1;
    	for(int i=2;i<=n;++i)
    	{
    		if((a[i]>=x)!=val)
    		{
    			s.insert(node{i-len,i-1,val});
    			val=(a[i]>=x);len=1;
    		}
    		else len++;
    	}
    	s.insert(node{n-len+1,n,val});
    	s.insert(node{n+1,n+1,1});
    	for(int i=1;i<=m;++i)
    	{
    		if(pan[i]==0)//升序 
    		{
    			int lin=r[i]-l[i]+1-sum(l[i],r[i]);//cout<<"lin="<<lin<<endl;
    			tuiping(l[i],l[i]+lin-1,0);
    			tuiping(l[i]+lin,r[i],1);
    		}
    		else
    		{
    			int lin=sum(l[i],r[i]);
    			tuiping(l[i],l[i]+lin-1,1);
    			tuiping(l[i]+lin,r[i],0);
    		}
    	}
        return sum(k,k);
    }
    
    void slove2()
    {
    	for(int i=1;i<=m;++i)pan[i]=(bool)read(),l[i]=read(),r[i]=read();
    	cin>>k;
    	int ans=0;
    	ll=1;rr=n;//cout<<check(5)<<endl;;
    	while(ll<=rr)
    	{
    		int mid=(ll+rr)>>1;
    		if(check(mid))
    		{
    			ll=mid+1;
    			ans=mid;
    		}
    		else rr=mid-1;
    	}
    	cout<<ans;
    }
    
    
    
    int main()
    {
    	//freopen("seq.in","r",stdin);
    	//freopen("seq.out","w",stdout);
    	cin>>n>>m;
    	for(int i=1;i<=n;++i)a[i]=read();
    	slove2();
    	fclose(stdin);fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    根据屏幕大小,加载不同大小的图片
    规范命名CSS
    iframe框架加载完成后执行函数
    js获取IP地址
    80端口被System占用 造成Apache不能启动的解方案
    自定义一个仿Spinner
    让你的代码量减少3倍!使用kotlin开发Android(一)
    屏幕适配
    一个旋转菜单
    手势监听GestureDetector 案例
  • 原文地址:https://www.cnblogs.com/wljss/p/11559916.html
Copyright © 2011-2022 走看看