bzoj 4552: [Tjoi2016&Heoi2016]排序 二分答案+线段树

原创 2016年08月30日 18:54:05

题意:有一个n的某个排列,要求资瓷两个操作:

0 l r表示将[l,r]这个区间按升序排序

1 l r降序排序

最后问位置q上的数是多少


分析:这题题解好劲啊!!!

首先二分一下答案(蒟蒻表示根本想不到)

判断ans是否不小于mid

若a[i]<mid则a[i]=0否则a[i]=1

然后用线段树维护一下就好了


代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define N 200005
using namespace std;

int n,m,a[N];
struct quer{int op,l,r;}q[N];
struct tree{int l,r,tag,s0,s1;}t[N*10];

void pushdown(int d)
{
	if (t[d].tag==-1||t[d].l==t[d].r) return;
	if (t[d].tag==0)
	{
		t[d*2].tag=t[d*2+1].tag=0;
		t[d*2].s1=t[d*2+1].s1=0;
		t[d*2].s0=t[d*2].r-t[d*2].l+1;
		t[d*2+1].s0=t[d*2+1].r-t[d*2+1].l+1;
		t[d].tag=-1;
	}else
	{
		t[d*2].tag=t[d*2+1].tag=1;
		t[d*2].s0=t[d*2+1].s0=0;
		t[d*2].s1=t[d*2].r-t[d*2].l+1;
		t[d*2+1].s1=t[d*2+1].r-t[d*2+1].l+1;
		t[d].tag=-1;
	}
}

void updata(int d)
{
	t[d].s0=t[d*2].s0+t[d*2+1].s0;
	t[d].s1=t[d*2].s1+t[d*2+1].s1;
}

void build(int d,int l,int r,int p)
{
	t[d].l=l;
	t[d].r=r;
	t[d].s0=t[d].s1=0;
	t[d].tag=-1;
	if (l==r)
	{
		if (a[l]<p) t[d].s0++;
		else t[d].s1++;
		return;
	}
	int mid=(l+r)/2;
	build(d*2,l,mid,p);
	build(d*2+1,mid+1,r,p);
	updata(d);
}

int query(int d,int x,int y)
{
	pushdown(d);
	if (t[d].l==x&&t[d].r==y) return t[d].s0;
	int mid=(t[d].l+t[d].r)/2;
	if (y<=mid) return query(d*2,x,y);
	else if (x>mid) return query(d*2+1,x,y);
	else return query(d*2,x,mid)+query(d*2+1,mid+1,y);
}

void ins0(int d,int x,int y)
{
	pushdown(d);
	if (t[d].l==x&&t[d].r==y)
	{
		t[d].s1=0;
		t[d].s0=t[d].r-t[d].l+1;
		t[d].tag=0;
		return;
	}
	int mid=(t[d].l+t[d].r)/2;
	if (y<=mid) ins0(d*2,x,y);
	else if (x>mid) ins0(d*2+1,x,y);
	else
	{
		ins0(d*2,x,mid);
		ins0(d*2+1,mid+1,y);
	}
	updata(d);
}

void ins1(int d,int x,int y)
{
	pushdown(d);
	if (t[d].l==x&&t[d].r==y)
	{
		t[d].s0=0;
		t[d].s1=t[d].r-t[d].l+1;
		t[d].tag=1;
		return;
	}
	int mid=(t[d].l+t[d].r)/2;
	if (y<=mid) ins1(d*2,x,y);
	else if (x>mid) ins1(d*2+1,x,y);
	else
	{
		ins1(d*2,x,mid);
		ins1(d*2+1,mid+1,y);
	}
	updata(d);
}

int find(int d,int x)
{
	if (t[d].l==t[d].r)
		if (t[d].s0) return 0;
		else return 1;
	pushdown(d);
	int mid=(t[d].l+t[d].r)/2;
	if (x<=mid) return find(d*2,x);
	else return find(d*2+1,x);
}

int main()
{
	//freopen("4552.in","r",stdin);
	//freopen("test.out","w",stdout);
	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",&q[i].op,&q[i].l,&q[i].r);
	int w;
	scanf("%d",&w);
	int l=1,r=n; 
	while (l<=r)
	{
		int mid=(l+r)/2;
		build(1,1,n,mid);
		for (int i=1;i<=m;i++)
		{
			int x=query(1,q[i].l,q[i].r),y=q[i].r-q[i].l+1-x;
			if (q[i].op==0)
			{
				if (x) ins0(1,q[i].l,q[i].l+x-1);
				if (q[i].l+x<=q[i].r) ins1(1,q[i].l+x,q[i].r);
			}else
			{
				if (y) ins1(1,q[i].l,q[i].l+y-1);
				if (q[i].l+y<=q[i].r) ins0(1,q[i].l+y,q[i].r);
			}
		}
		if (find(1,w)==1) l=mid+1;
		else r=mid-1;
	}
	printf("%d",l-1);
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

[BZOJ4552][Tjoi2016&Heoi2016][线段树][二分]排序

题意求给定序列经过给定排序网络后的第k个元素鏼爷15年论文小例题%%%二分答案x,原数列中大于等于x的设为1,小于x的设为0。 每一次排序的区间[l,r]中,有k1个0,k2个1,那么升序就把前k1...
  • Coldef
  • Coldef
  • 2017年02月13日 20:01
  • 148

BZOJ4552: [Tjoi2016&Heoi2016]排序 线段树

BZOJ4552: [Tjoi2016&Heoi2016]排序 Time Limit: 60 Sec  Memory Limit: 256 MB Submit: 587  Solved: ...
  • Oakley_
  • Oakley_
  • 2016年12月30日 20:01
  • 186

【TJOI & HEOI 2016】【JZOJ 4605】 【BZOJ 4552】排序

Description 序列长度为nn,排序次数为mm 100%1≤n,m≤100000100\%1\leq n,m\leq 100000 Time Limits:6000msTime\ Lim...

bzoj4552【TJOI2016&HEOI2016】排序

二分答案+线段树

【bzoj4551】【Tjoi2016】【Heoi2016】【树】【线段树】

题目大意给出一棵有根树,有很多操作,给一个点打标记,查询到跟路上最近那个点打了标记。题解我的做法是先搞出dfs序,打标记只会影响子树,线段树区间修改就行了,查询就是单点查询。注意空点不下传标记,不然空...

【bzoj4553】【Tjoi2016】【Heoi2016】【序列】【树套树】【线段树套线段树】

题目大意给出长度为n的序列a,有m次变化。每次变化把a[x]改成b[x],一个位可以多次修改,变化相对独立。选出最长字串,在m次变化与原串中都是不下降的。题解通过分析可知,设f[i]为前i位中一定选了...

BZOJ 4552 排序 Heoi2016

记得当年省选的时候 这道题连暴力都没写对(尴尬ing) (当年天真的认为sort是左闭右闭的hhhhhh) 思路: 首先 二分答案线段树 首先二分答案,然后需要知道进行m次排序后p位置上的...

[BZOJ4556][Tjoi2016&Heoi2016]字符串(后缀数组+二分+st表+主席树)

题目描述传送门题解思路清晰就很好写… 首先二分答案mid 找到Suffix(c),在height数组中向左向右分别二分最远的lcp为mid的后缀 用st表实现O(1)O(1)查询 然后就判断[...

BZOJ4554(Tjoi2016&Heoi2016)[游戏]--二分图最大匹配

bzoj4554
  • CHNWJD
  • CHNWJD
  • 2017年06月29日 16:34
  • 472

【二分图最大匹配】BZOJ4554 [Tjoi2016&Heoi2016]游戏

题面在这里典型的二分图最大匹配……只需要把每行/每列的空隙看作点 空地就看作空隙之间的联系 建边刷即可这里用了时间戳标记,新姿势Get示例程序:...
  • linkfqy
  • linkfqy
  • 2017年07月26日 14:48
  • 460
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:bzoj 4552: [Tjoi2016&Heoi2016]排序 二分答案+线段树
举报原因:
原因补充:

(最多只允许输入30个字)