关闭

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

143人阅读 评论(0) 收藏 举报
分类:

题意:有一个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);
}


0
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

bzoj刷题(shui)记录

放假刷了一个月的水题,集中写一下题解吧。bzoj1858:线段树随便维护一下。 code bzoj2705:莫比乌斯反演裸题。 code bzoj1202:并查集,但是我写了一种跟floyd很像的...
  • FZHvampire
  • FZHvampire
  • 2015-08-31 11:26
  • 1639

[BZOJ3196]二逼平衡树(线段树套splay)

花费了不知多少页来描述我们的心情 却不知为何填不满一行的空白
  • Clove_unique
  • Clove_unique
  • 2016-04-29 09:59
  • 1657

【BZOJ4540】【Hnoi2016】序列 线段树

Claris劲啊!CA劲啊! %%%两位线段树做法传送门在这里和这里 逆向题解时间到: 首先将询问按照终点排序,并且一边从到遍历,不妨设当前遍历到了点,对于之前的每个点,我们维护两个值和。 其中...
  • qq_34637390
  • qq_34637390
  • 2016-05-04 11:35
  • 1781

【二分+线段树】BZOJ4552(Tjoi2016&Heoi2016)[排序]题解

题目概述给出一个 nn 的排列,对其进行 mm 次局部排序:将 [L,R][L,R] 升序或降序排序。问最后 pospos 上的数。解题报告又是二分神题Orz,先二分答案 midmid ,就可以把序列...
  • zzkksunboy
  • zzkksunboy
  • 2017-12-19 21:17
  • 92

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

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

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

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

[Treap套权值线段树 线段树分裂与合并] BZOJ 4552 [Tjoi2016&Heoi2016]排序

线段树合并写了不少 分裂是第一次 直接每一个有序区间用一棵权值线段树维护有哪些数 外层用treap维护顺序 然后排序就把代表这段的很多颗线段树合并在一起 两端处会割开某个有序区间 会涉及分裂操作...
  • u014609452
  • u014609452
  • 2017-01-30 19:34
  • 459

TJOI2016&HEOI2016 排序 线段树+二分答案

题目链接: bzoj点我:-) 洛谷点我:-) 题目描述: 在2016年,佳媛姐姐喜欢上了数字序列。因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他。这个难题是这...
  • miaomiao_ymxl
  • miaomiao_ymxl
  • 2017-03-10 23:46
  • 96

【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...
  • lyd_7_29
  • lyd_7_29
  • 2016-07-11 17:02
  • 225

洛谷P2824:[HEOI2016]排序 (二分答案+线段树)

题目传送门:https://www.luogu.org/problemnew/show/P2824题目分析:这题是我上生物课的时候花20分钟想到的。我们可以像整体二分那样,先枚举一个数作为标准,然后只...
  • KsCla
  • KsCla
  • 2017-11-18 09:38
  • 106
    个人资料
    • 访问:202460次
    • 积分:9401
    • 等级:
    • 排名:第2247名
    • 原创:827篇
    • 转载:3篇
    • 译文:0篇
    • 评论:35条
    欢迎qq交流
    qq:763647200
    文章分类
    最新评论