【BZOJ 3196】 Tyvj 1730 二逼平衡树 分块

分块 就是分块嘛!

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cmath>
#define MAXN 1000000
#define INF 1000000000
#define MO 233333333
#define LL long long
using namespace std;
int num[300][300];
int init[50000+1];
int n,m;
int cnt,lenth;
int Find(int tmp[300],int k)
{
	int L=1,R=tmp[0];
	while(L<R)
	{
		int mid=(L+R)/2;
		if(tmp[mid]>=k) R=mid;
		else L=mid+1;
	}
	if(tmp[L]>=k)return L-1;
	return L;
}
int Rank(int L,int R,int k)
{
	int ans=0;
	int s=(L+lenth-1)/lenth,t=(R+lenth-1)/lenth;// cout<<lenth<<endl;
	if(s!=t)
	{
		for(int i=L;i<=lenth*s;i++)
			if(init[i]<k)
				ans++;
		s++;
		for(int i=R;i>=lenth*(t-1)+1;i--)
			if(init[i]<k)
				ans++;
		for(int i=s;i<t;i++)
			ans+=Find(num[i],k);
	}
	else
	{
		for(int i=L;i<=R;i++)
			if(init[i]<k)
				ans++;
	}
	return ans+1;
}
int Kth(int L,int R,int k)
{
	int s=0,t=100000000;
	int ans=0;
	while(s<t)
	{
		int mid=(s+t)/2;
		if(Rank(L,R,mid)>k) t=mid;
		else s=mid+1,ans=mid;
	}
	return ans;
}
void Change(int loc,int k)
{
	init[loc]=k;
	int tmp=(loc+lenth-1)/lenth;
	for(int i=1;i<=num[tmp][0];i++)
		num[tmp][i]=init[(tmp-1)*lenth+i];
	sort(num[tmp]+1,num[tmp]+num[tmp][0]+1);
}
int Before(int L,int R,int k)
{
	int s=(L+lenth-1)/lenth,t=(R+lenth-1)/lenth;
	int mmax=-1;//cout<<s<<‘ ‘<<t<<endl;
	if(s!=t)
	{
		for(int i=L;i<=s*lenth;i++)
			if(init[i]<k)
				mmax=max(mmax,init[i]);
		s++;
		for(int i=R;i>=(s-1)*lenth;i--)
			if(init[i]<k)
				mmax=max(mmax,init[i]);
		for(int i=s;i<t;i++)
		{
			int x=Find(num[i],k);
			if(x!=0)
				mmax=max(num[i][x],mmax);
		}
	}
	else
	{
		for(int i=L;i<=R;i++)
			if(init[i]<k)
				mmax=max(mmax,init[i]);
	}
	return mmax;
}
int Find_After(int tmp[300],int k)
{
	int L=1,R=tmp[0];
	while(L<R)
	{
		int mid=(L+R)/2;
		if(tmp[mid+1]<=k) L=mid+1;
		else R=mid;
	}
	if(tmp[L]<=k) return L+1;
	return L;
}
int After(int L,int R,int k)
{
	int s=(L+lenth-1)/lenth,t=(R+lenth-1)/lenth;
	int mmin=100000000+1;
	if(s!=t)
	{
		for(int i=L;i<=s*lenth;i++)
			if(init[i]>k)
				mmin=min(mmin,init[i]);
		s++;
		for(int i=R;i>=(s-1)*lenth;i--)
			if(init[i]>k)
				mmin=min(mmin,init[i]);
		for(int i=s;i<t;i++)
		{
			int x=Find_After(num[i],k);
			if(x!=num[i][0]+1)
				mmin=min(num[i][x],mmin);
		}
	}
	else
	{
		for(int i=L;i<=R;i++)
			if(init[i]>k)
				mmin=min(mmin,init[i]);
	}
	return mmin;
}
int main()
{
//	freopen("a.in","r",stdin);
	cin>>n>>m; //cout<<n<<endl;
	for(int i=1;i<=n;i++) scanf("%d",&init[i]);
	lenth=sqrt(n)+2;
	cnt=lenth;
	for(int i=1;i<=cnt;i++)
	{
		for(int j=1;j<=lenth;j++)
			num[i][j]=init[(i-1)*lenth+j];
		sort(num[i]+1,num[i]+lenth+1);
		num[i][0]=lenth;
	}
	if(n%lenth!=0)
	{
		cnt++;
		num[cnt][0]=n%lenth;
		for(int i=1;i<=num[cnt][0];i++)
			num[cnt][i]=init[(cnt-1)*lenth+i];
		sort(num[cnt]+1,num[cnt]+1+num[cnt][0]);
	}
	int L,R,pos,opt,k;
	for(int i=1;i<=m;i++)
	{
		scanf("%d",&opt);
		switch (opt)
		{
			case 1:
				{
					scanf("%d %d %d",&L,&R,&k);
					printf("%d\n",Rank(L,R,k));
					break;
				}
			case 2:
				{
					scanf("%d %d %d",&L,&R,&k);
					printf("%d\n",Kth(L,R,k));
					break;
				}
			case 3:
				{
					scanf("%d %d",&pos,&k);
					Change(pos,k);
					break;
				}
			case 4:
				{
					scanf("%d %d %d",&L,&R,&k);
					printf("%d\n",Before(L,R,k));
					break;
				}
			case 5:
				{
					scanf("%d %d %d",&L,&R,&k);
					printf("%d\n",After(L,R,k));
					break;
				}
		}

	}

	return 0;
}
时间: 2024-10-17 03:16:51

【BZOJ 3196】 Tyvj 1730 二逼平衡树 分块的相关文章

bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,

BZOJ 3196: Tyvj 1730 二逼平衡树( 树套树 )

这道题做法应该很多吧.... 我用了线段树套treap.... -------------------------------------------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<cstdlib> #include<ios

bzoj 3196: Tyvj 1730 二逼平衡树

我操,,,,我记得这个sb题,,搞了一整天,(吐槽,本来开心去洛谷提交,结果不一样,mdzz) 树套树,,,各种套... 都是在区间内最基本的查询 1 #include<bits/stdc++.h> 2 #define N 100005 3 #define LL long long 4 #define inf 0x3f3f3f3f 5 using namespace std; 6 inline int ra() 7 { 8 int x=0,f=1; char ch=getchar(); 9 w

BZOJ 3196 Tyvj 1730 二逼平衡树 ——树状数组套主席树

[题目分析] 听说是树套树.(雾) 怒写树状数组套主席树,然后就Rank1了.23333 单点修改,区间查询+k大数查询=树状数组套主席树. [代码] #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <set> #include <map> #include <string> #include <alg

3196: Tyvj 1730 二逼平衡树

http://www.lydsy.com/JudgeOnline/problem.php?id=3196 分析: 带区间查询和名次询问,线段树套treap 操作1: 查询k在区间内的排名. 求出k-1的名次+1就是k的名次 操作2:查询区间内排名为k的值. 二分枚举权值,调用操作1 操作3:修改某一位值上的数值. 在树上先删除,再插入 操作4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 操作5.查询k在区间内的后继(后继定义为大于x,且最小的数) 在treap树上遍历 //83516

【BZOJ 3196】Tyvj 1730 二逼平衡树

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 842  Solved: 350 [Submit][Status] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,

[Tyvj 1730] 二逼平衡树

先来一发题面QwQ [TYVJ1730]二逼平衡树 Time Limit:2 s   Memory Limit:512 MB Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作第二行有n个数

【分块】bzoj3196 Tyvj 1730 二逼平衡树

分块 或 树套树. 在每个块中维护一个有序表,查询时各种二分,全都是分块的经典操作,就不详细说了. 块的大小定为sqrt(n*log2(n))比较快. 1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 int sum,sz,l[400],r[400],num[51001],a[51001],b[5100

【函数式权值分块】【分块】bzoj3196 Tyvj 1730 二逼平衡树

#include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define N 50001 #define SQRT 227 int n,m,xs[N],ys[N],ks[N],op[N],en,ma[100001],en2,a[100001]; int num[N],l[SQRT],r[SQRT],sumv[SQRT],sum=1;//分块 int num2[100001],l2[