loj #2055. 「TJOI / HEOI2016」排序(二分+线段树)

题目链接:https://loj.ac/problem/2055


二分答案之后变为01序列,每次排序直接将区间赋值为1或者0即可,用线段树维护即可。


代码:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+5;
template<typename Tp>
struct seg
{
	#define lson l,mid,rt<<1
	#define rson mid+1,r,rt<<1|1
	#define root l,r,rt
	Tp tr[MAXN<<2],lazy[MAXN<<2];
	inline void push_up(int rt)
	{
		tr[rt]=tr[rt<<1]+tr[rt<<1|1];
	}
	inline void push_down(int l,int r,int rt)
	{
		if(lazy[rt]!=-1)
		{
			int mid=(l+r)>>1;
			tr[rt<<1]=(mid-l+1)*lazy[rt];
			tr[rt<<1|1]=(r-mid)*lazy[rt];
			lazy[rt<<1]=lazy[rt];
			lazy[rt<<1|1]=lazy[rt];
			lazy[rt]=-1;
		}
	}
	void build(int l,int r,int rt,int *a)
	{
		lazy[rt]=-1;
		if(l==r)
		{
			tr[rt]=a[l];
			return; 
		}
		int mid=(l+r)>>1;
		build(lson,a);
		build(rson,a);
		push_up(rt);
	}
	void update(int L,int R,Tp val,int l,int r,int rt)
	{
		if(L>R) return; 
		if(L<=l&&r<=R)
		{
			tr[rt]=(r-l+1)*val;
			lazy[rt]=val;
			return ;
		}
		push_down(l,r,rt);
		int mid=(l+r)>>1;
		if(L<=mid)
			update(L,R,val,lson);
		if(mid<R)
			update(L,R,val,rson);
		push_up(rt);
	}
	Tp query(int L,int R,int l,int r,int rt)
	{
		if(L<=l&&r<=R)
			return tr[rt];
		push_down(l,r,rt);
		int mid=(l+r)>>1;
		Tp ret=0;
		if(L<=mid)
			ret+=query(L,R,lson);
		if(mid<R)
			ret+=query(L,R,rson);
		return ret;
	}
};
struct operatation
{
	int op,l,r;
}sv[MAXN];
inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void rea(int &x)
{
	char c=nc();x=0;
	for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}
seg<int> se;
int a[MAXN],p[MAXN];
int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	int n,m,k;
	rea(n);rea(m);
	for(int i=1;i<=n;i++)
	{
		rea(a[i]);
	}
	for(int i=1;i<=m;i++)
	{
		rea(sv[i].op);rea(sv[i].l);rea(sv[i].r);
	}
	rea(k);
	int l=1,r=n,ans=1;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		for(int i=1;i<=n;i++)
		{
			p[i]=(a[i]>=mid);
		}
		se.build(1,n,1,p);
		for(int i=1;i<=m;i++)
		{
			int op=sv[i].op;
			int l=sv[i].l;
			int r=sv[i].r;
			int cnt=se.query(l,r,1,n,1);
			//cout<<cnt<<" "<<r-l+1<<endl;
			if(op==0)
			{
				se.update(r-cnt+1,r,1,1,n,1);
				se.update(l,r-cnt,0,1,n,1);
			}
			else
			{
				se.update(l+cnt,r,0,1,n,1);
				se.update(l,l+cnt-1,1,1,n,1);
			}
		}
		int num=se.query(k,k,1,n,1);
		//cout<<mid<<endl;
		if(num)
		{
			ans=mid;
			l=mid+1;
		}
		else
		{
			r=mid-1;
		}
	}
	printf("%d\n",ans);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值