hdu1754(splay tree 单点更新,成段查询)
题意就是简单的点更新,成段查询。
splay tree 果真是常数比较大的log(n)操作。 比线段树还慢了这么多。
// // main.cpp // splay // // Created by 陈加寿 on 16/3/25. // Copyright © 2016年 chenhuan001. All rights reserved. // #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; //来一发点更新,成段查询 #define MAXN 1001000 #define INF 1001000000 struct Splay_Tree { int cnt, rt; struct node { int K,mxk; int key, size, fa, son[2]; void set(int _key, int _size, int _fa,int _K) { mxk = K = _K;//这个表示这个节点的值 key = _key;//这个为ID size=_size; fa=_fa; son[0]=son[1]=0; } }T[MAXN]; inline void init() { cnt=0; T[cnt++].set(0, 0, 0, 0);// rt = 0; //初始化的时候,把0这个节点的K设置为INF } inline void PushUp(int x) { //这一步就很关键了 T[x].size=T[T[x].son[0]].size+T[T[x].son[1]].size+1; T[x].mxk = max(T[x].K,max(T[T[x].son[0]].mxk,T[T[x].son[1]].mxk)); } inline void Rotate(int x, int p) //0左旋 1右旋 { int y=T[x].fa; T[y].son[!p]=T[x].son[p]; T[T[x].son[p]].fa=y; T[x].fa=T[y].fa; if(T[x].fa) T[T[x].fa].son[T[T[x].fa].son[1] == y]=x; T[x].son[p]=y; T[y].fa=x; PushUp(y);//先更新y PushUp(x);//再更新x } void Splay(int x, int To) //将x节点插入到To的子节点中 { while(T[x].fa != To) { if(T[T[x].fa].fa == To) Rotate(x, T[T[x].fa].son[0] == x); else { int y=T[x].fa, z=T[y].fa; int p=(T[z].son[0] == y); if(T[y].son[p] == x) Rotate(x, !p), Rotate(x, p); //之字旋 else Rotate(y, p), Rotate(x, p); //一字旋 } } if(To == 0) rt=x; } int find(int key) //返回值为key的节点 若无返回0 若有将其转移到根处 { int x=rt; while(x && T[x].key != key) x=T[x].son[key > T[x].key]; if(x) Splay(x, 0); return x; } int prev() //返回比根值小的最大值 若无返回0 若有将其转移到根处 { int x=T[rt].son[0]; if(!x) return 0; while(T[x].son[1]) x=T[x].son[1]; Splay(x, 0); return x; } int next() //返回比根值大的最小值 若无返回0 若有将其转移到根处 { int x=T[rt].son[1]; if(!x) return 0; while(T[x].son[0]) x=T[x].son[0]; Splay(x, 0); return x; } void Insert(int key,int K) //插入key 并且将该节点转移到根处 { if(!rt) T[rt = cnt++].set(key, 1, 0, K); else { int x=rt, y=0; while(x) { y=x; x=T[x].son[key > T[x].key]; } T[x = cnt++].set(key, 1, y, K); T[y].son[key > T[y].key]=x; Splay(x, 0); } } void Delete(int key) //删除值为key的节点 若有重点只删其中一个 x的前驱移动到根处 { int x=find(key); if(!x) return; int y=T[x].son[0]; while(T[y].son[1]) y=T[y].son[1]; int z=T[x].son[1]; while(T[z].son[0]) z=T[z].son[0]; if(!y && !z) { rt=0; return; } if(!y) { Splay(z, 0); T[z].son[0]=0; PushUp(z); return; } if(!z) { Splay(y, 0); T[y].son[1]=0; PushUp(y); return; } Splay(y, 0); Splay(z, y); T[z].son[0]=0; PushUp(z); PushUp(y); } int GetPth(int p) //获得第p小的节点 并将其转移到根处 { if(!rt) return 0; int x=rt; while(x) { if(p == T[T[x].son[0]].size+1) break; if(p>T[T[x].son[0]].size+1) { p-=T[T[x].son[0]].size+1; x=T[x].son[1]; } else x=T[x].son[0]; } Splay(x, 0); return x; } int GetRank(int key) //获得值<=key的节点个数 并将其转移到根处 若<key只需将<=换为< { if(!rt) return 0; int x=rt, ret=0, y=0; while(x) { y=x; if(T[x].key <= key) { ret+=T[T[x].son[0]].size+1; x=T[x].son[1]; } else x=T[x].son[0]; } Splay(y, 0); return ret; } }spt; int main() { //两种操作 //一、修改某个节点值 //二、区间查询 int n,m; while(scanf("%d%d",&n,&m)!=EOF) { spt.init(); for(int i=1;i<=n;i++) { int tmp; scanf("%d",&tmp); spt.Insert(i, tmp); } char sign; for(int i=0;i<m;i++) { getchar(); int a,b; scanf("%c %d %d",&sign,&a,&b); if(sign == 'Q') { if(a == b) { int id = spt.GetPth(a); printf("%d\n",spt.T[id].K);//区间只有一个点的时候 continue; } int idb = spt.GetPth(b); int ida = spt.GetPth(a); spt.Splay(idb, ida); int idson = spt.T[idb].son[0]; int mx = max( spt.T[idson].mxk ,max(spt.T[ida].K,spt.T[idb].K)); printf("%d\n",mx); } else { //更新操作 int id = spt.GetPth(a); spt.T[id].K = b; spt.PushUp(id); } } } return 0; }