UESTC #1919 一棵复杂的线段树

Description

给一个\(1 \sim n\)的排列,进行\(m\)次操作,可以将一个区间\([l,r]\)内的数升序排序或者降序排序,最后进行一次询问问第\(k\)个数字为多少。

Solution

二分答案,对于每一个二分的值\(x\),将原排列中小于等于\(x\)的数视为\(0\),大于\(x\)的树视为\(1\),用线段树维护,排序操作可以用线段树的区间赋值实现。

Code

/*
 Author: LargeDumpling
 Email: LargeDumpling@qq.com
 Edit History:
	2018-07-24	File created.
*/

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAXN=100050;
struct jz
{
	int l,r,typ;
}O[MAXN];
int num[MAXN],sum[MAXN<<2],tag[MAXN<<2],L[MAXN<<2],R[MAXN<<2],n,m,k;
void maintain(int root)
{
	sum[root]=sum[root<<1]+sum[root<<1|1];
	return;
}
void build(int root,int l,int r,int x)
{
	L[root]=l; R[root]=r; tag[root]=-1;
	if(l==r)
	{
		sum[root]=(num[l]<=x)?0:1;
		return;
	}
	int mid=(l+r)>>1;
	build(root<<1,l,mid,x);
	build(root<<1|1,mid+1,r,x);
	maintain(root);
	return;
}
void down(int root)
{
	if(tag[root]==-1) return;
	sum[root<<1]=tag[root]*(R[root<<1]-L[root<<1]+1);
	tag[root<<1]=tag[root];
	sum[root<<1|1]=tag[root]*(R[root<<1|1]-L[root<<1|1]+1);
	tag[root<<1|1]=tag[root];
	tag[root]=-1;
	return;
}
void change(int root,int l,int r,int x)
{
	if(r<l) return; //because of line 98, 99, 103, 104, ignore this will cause a Wrong Answer.
	if(l<=L[root]&&R[root]<=r)
	{
		sum[root]=x*(R[root]-L[root]+1);
		tag[root]=x;
		return;
	}
	down(root);
	int mid=(L[root]+R[root])>>1;
	if(l<=mid) change(root<<1,l,r,x);
	if(mid<r) change(root<<1|1,l,r,x);
	/*if(l<=R[root<<1]) change(root<<1,l,r,x);
	if(R[root<<1]<r) change(root<<1|1,l,r,x);*/ //this will cause a Runtime Error.
	maintain(root);
	return;
}
int query(int root,int l,int r)
{
	if(r<l) return 0;
	if(l<=L[root]&&R[root]<=r) return sum[root];
	down(root);
	int ans=0,mid=(L[root]+R[root])>>1;
	if(l<=mid) ans+=query(root<<1,l,r);
	if(mid<r) ans+=query(root<<1|1,l,r);
	/*if(l<=R[root<<1]) ans+=query(root<<1,l,r);
	if(R[root<<1]<r) ans+=query(root<<1|1,l,r);*/
	return ans;
}
void read1n(int &x)
{
	char ch;
	for(ch=getchar();ch<'0'||'9'<ch;ch=getchar());
	for(x=0;'0'<=ch&&ch<='9';ch=getchar())
		x=(x<<1)+(x<<3)+ch-'0';
	return;
}
bool check(int x)
{
	int cnt0,cnt1;
	build(1,1,n,x);
	for(int i=1;i<=m;i++)
	{
		cnt1=query(1,O[i].l,O[i].r);
		cnt0=O[i].r-O[i].l+1-cnt1;
		if(O[i].typ)
		{
			change(1,O[i].l,O[i].l+cnt1-1,1);
			change(1,O[i].r-cnt0+1,O[i].r,0);
		}
		else
		{
			change(1,O[i].l,O[i].l+cnt0-1,0);
			change(1,O[i].r-cnt1+1,O[i].r,1);
		}
	}
	return query(1,k,k)==0;
}
int main()
{
	int l,r,mid;
	read1n(n); read1n(k);
	for(int i=1;i<=n;i++)
		read1n(num[i]);
	read1n(m);
	for(int i=1;i<=m;i++)
	{
		read1n(O[i].typ);
		read1n(O[i].l);
		read1n(O[i].r);
	}
	l=0; r=n;
	while(l<r-1)
	{
		mid=(l+r)>>1;
		if(check(mid)) r=mid;
		else l=mid;
	}
	printf("%d\n",r);
	fclose(stdin);
	fclose(stdout);
	return 0;
}

Other thing

傅大爷数据出的太好了,把我原来线段树的写法卡疯了。

posted @ 2018-07-24 20:24  LargeDumpling  阅读(226)  评论(0编辑  收藏  举报