HDU 1754区间最值 & SPLAY

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 1754区间最值 & SPLAY相关的知识,希望对你有一定的参考价值。

真是亲切的1754啊。。第一道傻逼版的线段树做的是这个,后来学了zkw做的是这个,在后来决定打lrj线段树又打了一遍,如今再用splay和老朋友见面

  技术分享  从上到下依次为:加了读入优化的splay,splay,加了inline的splay,边读入边建树的lrj线段树,zkw线段树,以及线段树初体验

题意

  单点修改询问区间最值。

SOL:

  平衡树真是优美的植物,像陀螺通过不断的优雅的旋转体现自身的平衡与美感。

  对于splay的区间问题,我们利用序号来建树,当要查询一个区间时,我们把这个区间左端点的前一个点旋到根,那么这个区间就都在根的右子树中,再将右端点的后一个点旋到根的右儿子,那么整段区间就都在根的右儿子的左儿子上了。整个过程利用BST的性质非常显然。当然为了防止越界我们把整段序列向右平移一格,便于维护。

  对于这样的询问,splay与线段树没有什么区别,线段树是分割线段,而splay是取出线段,然后标记、最值、和什么的都一样了,所以线段树能实现的splay都能实现(除了可持久化。

  当然对比上图,我们还是能看出它们之间的优劣。。zkw线段树继承了树状数组的优点,代码短效率高——但是貌似细节巨多。。我现在也忘得差不多了。。lrj线段树由于是nlgn的建树所以看起来稍微慢一点,实际上的效率应该在正常水平左右,打了一些注释所以代码长度显得长一些。 而splay。。。内存我多开了很多没有用的数组显得大一点。代码长度尽管以前没有用现在这么多的头文件。。但由于操作非常多尽管已经尽力把splay写得非常紧凑但还是要长处不少。

  在速度上实现得和线段树差不多,看起来也挺好。

CODE:

/*==========================================================================
# Last modified: 2016-02-19 15:23
# Filename: hdu1754.cpp
# Description: 
==========================================================================*/
#define me AcrossTheSky 
#include <cstdio> 
#include <cmath> 
#include <ctime> 
#include <string> 
#include <cstring> 
#include <cstdlib> 
#include <iostream> 
#include <algorithm> 
  
#include <set> 
#include <map> 
#include <stack> 
#include <queue> 
#include <vector> 
#define lowbit(x) (x)&(-x) 
#define INF 1070000000 
#define FOR(i,a,b) for((i)=(a);(i)<=(b);(i)++) 
#define FORP(i,a,b) for(int i=(a);i<=(b);i++) 
#define FORM(i,a,b) for(int i=(a);i>=(b);i--) 
#define ls(a,b) (((a)+(b)) << 1) 
#define rs(a,b) (((a)+(b)) >> 1) 
#define maxn 300000
#define getlc(a) ch[(a)][0]
#define getrc(a) ch[(a)][1]
using namespace std; 
typedef long long ll; 
typedef unsigned long long ull; 

template<class T> inline
void read(T& num) {
    bool start=false,neg=false;
    char c;
    num=0;
    while((c=getchar())!=EOF) {
        if(c==‘-‘) start=neg=true;
        else if(c>=‘0‘ && c<=‘9‘) {
            start=true;
            num=num*10+c-‘0‘;
        } else if(start) break;
    }
    if(neg) num=-num;
}
/*==================split line==================*/ 
int root;
int n,m;
int fa[maxn],ch[maxn][2],_max[maxn],v[maxn],s[maxn],a[maxn];
int cnt=0;
int null;
inline void updata(int node){
	s[node]=1+s[getlc(node)]+s[getrc(node)];
	_max[node]=max(v[node],max(_max[getlc(node)],_max[getrc(node)]));
}
inline void rotate(int x){
	int p=fa[x],q=fa[p],d=ch[p][1]==x;
	fa[ch[p][d]=ch[x][d^1]]=p; updata(p);
	fa[ch[x][d^1]=p]=x; 
	fa[x]=q;
	if (q){
		if (ch[q][0]==p) ch[q][0]=x;
		else if (ch[q][1]==p) ch[q][1]=x;
	}
	updata(x);
}
inline void splay(int x,int &aim){
	for(int y;(y=fa[x])!=aim;rotate(x))
		if (fa[y]!=aim) rotate((getlc(y)==x)==(getlc(fa[y])==y)?y:x);
	if (aim==0) root=x;
	updata(x);
}
inline void change(int node,int x){
	splay(node,null);
	v[node]=x;
	updata(node);
}
inline void query(int l,int r){
	splay(l-1,null);
	splay(r+1,root);
	printf("%d\n",_max[getlc(getrc(root))]);

}
inline int build(int sz){
	if (sz<=0) return 0;
	int t=build(sz/2),node=++cnt;
	fa[ch[node][0]=t]=node; 
	fa[ch[node][1]=build(sz-sz/2-1)]=node;
	if (node==1 || node==n+2) v[node]=-INF;
		else v[node]=a[node];
	updata(node);
	return node;
}
int main(){
	while (scanf("%d%d",&n,&m)!=EOF){
		cnt=0;
		memset(_max,0,sizeof(_max));
		memset(fa,0,sizeof(fa));
		memset(v,0,sizeof(v));
		FORP(i,1,n) read(a[i+1]);
		null=0;  
		root=build(n+2); 
		FORP(i,1,m){
			char s[2]; scanf("%s",s); int x,y; read(x); read(y);
			if (s[0]==‘Q‘) query(x+1,y+1);
			else change(x+1,y);
		}
	}
} 

 

以上是关于HDU 1754区间最值 & SPLAY的主要内容,如果未能解决你的问题,请参考以下文章

HDU--1754 区间最值(树状数组做法)

HDU--1754 区间最值(树状数组做法)

HDU - 1754 I Hate It (线段树区间求最值)

HDU 1754 I Hate It(线段树单点更新区间查询最值)

HDU 1754 I Hate It(线段树之单点更新,区间最值)

hdu 1754 I Hate It(线段树之 单点更新+区间最值)