[扫描线 树状数组 随机数列 优化] BZOJ 2221 [Jsoi2009]面试的考验

%%%JSB

随机一般有什么用呢?即: 对于一个点 i,然后从 1 到 i 递增的数列长度是 log。

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;

inline char nc(){
	static char buf[100000],*p1=buf,*p2=buf;
	if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
	return *p1++;
}

inline void read(int &x){
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

inline void read(ll &x){
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=500005;

namespace BIT{
	#define lowbit(i) ((i)&-(i))
	ll c[N]; int maxn;
	inline void init(int n){
		maxn=n; for (int i=1;i<=n;i++) c[i]=1LL<<61;
	}
	inline void add(int x,ll r){
		x=maxn-x+1;
		for (int i=x;i<=maxn && c[i]>r;i+=lowbit(i))
			c[i]=r;
	}
	inline ll query(int x,int y){
		x=maxn-x+1; y=maxn-y+1;
		ll ret=1LL<<61;
		for (int i=x;i>=y;i-=lowbit(i))
			ret=min(ret,c[i]);
		return ret;
	}
}

struct event{
	int l,r,idx;
	bool operator < (const event &B)const{
		return r<B.r;
	}
}eve[N];

int n,m;
ll a[N],ans[N];

int Q[N],l,r;
int small[N],big[N],F[N][40],G[N][40];

void Small(int x,int y){
	F[x][++F[x][0]]=y;
	for (int i=1;i<=G[y][0];i++)
	  if (a[G[y][i]]<a[x]) return Small(x,G[y][i]);
}
int Big(int x,int y){
	G[x][++G[x][0]]=y;
	for (int i=1;i<=F[y][0];i++)
		if (a[F[y][i]]>a[x]) return Big(x,F[y][i]);
}

inline void Solve(){
	l=1; r=0;
	for (int i=1;i<=n;i++){
		while (l<=r && a[i]<=a[Q[r]]) r--;
		if (l<=r) small[i]=Q[r];
		Q[++r]=i;
	}
	l=1; r=0;
	for (int i=1;i<=n;i++){
		while (l<=r && a[i]>=a[Q[r]]) r--;
		if (l<=r) big[i]=Q[r];
		Q[++r]=i;
	}
	BIT::init(n);
	for (int i=1;i<=n;i++){
		if (small[i]) Small(i,small[i]);
		if (big[i]) Big(i,big[i]);
//		if (*F[i]) check(F[i][*F[i]],i);
//		if (*G[i]) check(G[i][*G[i]],i);
	}
	int pnt=1;
	for (int i=1;i<=n;i++){
		for (int k=1;k<=F[i][0];k++)
			BIT::add(F[i][k],a[i]-a[F[i][k]]);
		for (int k=1;k<=G[i][0];k++)
			BIT::add(G[i][k],a[G[i][k]]-a[i]);
		while (pnt<=m && eve[pnt].r==i)
			ans[eve[pnt].idx]=BIT::query(eve[pnt].l,i),pnt++;
	}
}

int main()
{
	freopen("seq.in","r",stdin);
	freopen("seq.out","w",stdout);
	read(n);read(m);
	for (int i=1;i<=n;i++) read(a[i]);
	for (int i=1;i<=m;i++)
		read(eve[i].l),read(eve[i].r),eve[i].idx=i;
	sort(eve+1,eve+m+1);
	Solve();
	for (int i=1;i<=m;i++)
		printf("%lld\n",ans[i]);
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值