模板是从http://blog.csdn.net/crazy_ac/article/details/8034190这位大爷博客里找到的。。。但是在由于是功能挺全的一个版本,在一些题里可能维护了一些不必要的值(可能自己在操作步骤写丑了= =)而导致超时。。所以使用的时候还是要注意一下。。
上模板。。
1 #include<cstdio> 2 #include<cstdlib> 3 const int inf = ~0u>>2; 4 #define L ch[x][0] 5 #define R ch[x][1] 6 #define KT (ch[ ch[rt][1] ][0]) 7 const int maxn = 500010; 8 int lim; 9 struct SplayTree { 10 int sz[maxn]; 11 int ch[maxn][2]; 12 int pre[maxn]; 13 int rt,top; 14 inline void up(int x){ 15 sz[x] = cnt[x] + sz[ L ] + sz[ R ]; 16 } 17 inline void Rotate(int x,int f){ 18 int y=pre[x]; 19 ch[y][!f] = ch[x][f]; 20 pre[ ch[x][f] ] = y; 21 pre[x] = pre[y]; 22 if(pre[x]) ch[ pre[y] ][ ch[pre[y]][1] == y ] =x; 23 ch[x][f] = y; 24 pre[y] = x; 25 up(y); 26 } 27 inline void Splay(int x,int goal){//将x旋转到goal的下面 28 while(pre[x] != goal){ 29 if(pre[pre[x]] == goal) Rotate(x , ch[pre[x]][0] == x); 30 else { 31 int y=pre[x],z=pre[y]; 32 int f = (ch[z][0]==y); 33 if(ch[y][f] == x) Rotate(x,!f),Rotate(x,f); 34 else Rotate(y,f),Rotate(x,f); 35 } 36 } 37 up(x); 38 if(goal==0) rt=x; 39 } 40 inline void RTO(int k,int goal){//将第k位数旋转到goal的下面 41 int x=rt; 42 while(sz[ L ] != k-1) { 43 if(k < sz[ L ]+1) x=L; 44 else { 45 k-=(sz[ L ]+1); 46 x = R; 47 } 48 } 49 Splay(x,goal); 50 } 51 inline void vist(int x){ 52 if(x){ 53 printf("结点%2d : 左儿子 %2d 右儿子 %2d val:%2d sz=%d cnt:%d ",x,L,R,val[x],sz[x],cnt[x]); 54 vist(L); 55 vist(R); 56 } 57 } 58 void debug() { 59 puts(""); 60 vist(rt); 61 puts(""); 62 } 63 inline void Newnode(int &x,int c,int f){ 64 x=++top; 65 L = R = 0; 66 pre[x] = f; 67 sz[x]=1; cnt[x]=1; 68 val[x] = c; 69 } 70 inline void init(){ 71 ch[0][0]=ch[0][1]=pre[0]=sz[0]=0; 72 rt=top=0; cnt[0]=0; 73 } 74 inline void Insert(int &x,int key,int f){ 75 if(!x) { 76 Newnode(x,key,f); 77 Splay(x,0);//注意插入完成后splay 78 return ; 79 } 80 if(key==val[x]){ 81 cnt[x]++; 82 sz[x]++; 83 Splay(x,0);//注意插入完成后splay 84 return ; 85 }else if(key<val[x]) { 86 Insert(L,key,x); 87 } else { 88 Insert(R,key,x); 89 } 90 up(x); 91 } 92 void Del_root(){//删除根节点 93 int t=rt; 94 if(ch[rt][1]) { 95 rt=ch[rt][1]; 96 RTO(1,0); 97 ch[rt][0]=ch[t][0]; 98 if(ch[rt][0]) pre[ch[rt][0]]=rt; 99 } 100 else rt=ch[rt][0]; 101 pre[rt]=0; 102 up(rt); 103 } 104 void findpre(int x,int key,int &ans){//找前驱节点 105 if(!x) return ; 106 if(val[x] <= key){ 107 ans=x; 108 findpre(R,key,ans); 109 } else 110 findpre(L,key,ans); 111 } 112 void findsucc(int x,int key,int &ans){//找后继节点 113 if(!x) return ; 114 if(val[x]>=key) { 115 ans=x; 116 findsucc(L,key,ans); 117 } else 118 findsucc(R,key,ans); 119 } 120 inline int find_kth(int x,int k){ //第k小的数 121 if(k<sz[L]+1) { 122 return find_kth(L,k); 123 }else if(k > sz[ L ] + cnt[x] ) 124 return find_kth(R,k-sz[L]-cnt[x]); 125 else{ 126 Splay(x,0); 127 return val[x]; 128 } 129 } 130 int find(int x,int key){ 131 if(!x) return 0; 132 else if(key < val[x]) return find(L,key); 133 else if(key > val[x]) return find(R,key); 134 else return x; 135 } 136 int getmin(int x){ 137 while(L) x=L; return val[x]; 138 } 139 int getmax(int x){ 140 while(R) x=R; return val[x]; 141 } 142 //确定key的排名 143 int getrank(int x,int key,int cur){//cur:当前已知比要求元素(key)小的数的个数 144 if(key == val[x]) 145 return sz[L] + cur + 1; 146 else if(key < val[x]) 147 getrank(L,key,cur); 148 else 149 getrank(R,key,cur+sz[L]+cnt[rt]); 150 } 151 int get_lt(int x,int key){//小于key的数的个数 lt:less than 152 if(!x) return 0; 153 if(val[x]>=key) return get_lt(L,key); 154 return cnt[x]+sz[L]+get_lt(R,key); 155 } 156 int get_mt(int x,int key){//大于key的数的个数 mt:more than 157 if(!x) return 0; 158 if(val[x]<=key) return get_mt(R,key) ; 159 return cnt[x]+sz[R]+get_mt(L,key); 160 } 161 void del(int &x,int f){//删除小于lim的所有的数所在的节点 162 if(!x) return ; 163 if(val[x]>=lim){ 164 del(L,x); 165 } else { 166 x=R; 167 pre[x]=f; 168 if(f==0) rt=x; 169 del(x,f); 170 } 171 if(x) up(x); 172 } 173 inline void update(){ 174 del(rt,0); 175 } 176 int get_mt(int key) { 177 return get_mt(rt,key); 178 } 179 int get_lt(int key) { 180 return get_lt(rt,key); 181 } 182 void insert(int key) { 183 Insert(rt,key,0); 184 } 185 void Delete(int key) { 186 int node=find(rt,key); 187 Splay(node,0); 188 cnt[rt]--; 189 if(!cnt[rt])Del_root(); 190 } 191 int kth(int k) { 192 return find_kth(rt,k); 193 } 194 int cnt[maxn]; 195 int val[maxn]; 196 int lim; 197 }spt;
建树时候的函数
1 void built(int &x,int l,int r,int father) 2 { 3 if(l>r) 4 return ; 5 int mid=(l+r)/2; 6 Newnode(x,a[mid],father); 7 if(l<mid) 8 built(ch[x][0],l,mid-1,x); 9 if(r>mid) 10 built(ch[x][1],mid+1,r,x); 11 up(x); 12 }
然后是自己在poj3468中参照cxlove大爷改的lazy版本。。
1 #include<cstdio> 2 #include<cstdlib> 3 const int inf = ~0u>>2; 4 #define L ch[x][0] 5 #define R ch[x][1] 6 #define KT (ch[ ch[rt][1] ][0]) 7 #define ll long long 8 const int maxn = 100010; 9 int lim; 10 int a[maxn],n; 11 ll lazy[maxn],sum[maxn]; 12 using namespace std; 13 struct SplayTree { 14 int sz[maxn]; 15 int ch[maxn][2]; 16 int pre[maxn]; 17 int rt,top; 18 inline void up(ll x){ 19 sz[x] =sz[ L ] + sz[ R ]+1; 20 sum[x] = val[x] + sum[L]+sum[R]+lazy[x]; 21 } 22 inline void pushdown(int x) 23 { 24 if(lazy[x]) 25 { 26 if(L) 27 { 28 lazy[L]+=lazy[x]; 29 sum[L]+=lazy[x]*sz[L]; 30 } 31 if(R) 32 { 33 lazy[R]+=lazy[x]; 34 sum[R]+=lazy[x]*sz[R]; 35 } 36 val[x]+=lazy[x]; 37 lazy[x]=0; 38 } 39 } 40 inline void Rotate(int x,int f){ 41 int y=pre[x]; 42 pushdown(x); 43 pushdown(y); 44 ch[y][!f] = ch[x][f]; 45 pre[ ch[x][f] ] = y; 46 pre[x] = pre[y]; 47 if(pre[x]) ch[ pre[y] ][ ch[pre[y]][1] == y ] =x; 48 ch[x][f] = y; 49 pre[y] = x; 50 up(y); 51 } 52 inline void Splay(int x,int goal){//将x旋转到goal的下面 53 pushdown(x); 54 while(pre[x] != goal){ 55 if(pre[pre[x]] == goal) Rotate(x , ch[pre[x]][0] == x); 56 else { 57 int y=pre[x],z=pre[y]; 58 int f = (ch[z][0]==y); 59 if(ch[y][f] == x) Rotate(x,!f),Rotate(x,f); 60 else Rotate(y,f),Rotate(x,f); 61 } 62 } 63 up(x); 64 if(goal==0) rt=x; 65 } 66 void RTO(int k,int goal) { 67 int r=rt; 68 pushdown(r); 69 while(sz[ch[r][0]]!=k){ 70 if(k<sz[ch[r][0]]){ 71 r=ch[r][0]; 72 } else { 73 k-=(sz[ch[r][0]]+1); 74 r=ch[r][1]; 75 } 76 pushdown(r); 77 } 78 Splay(r,goal); 79 } 80 inline void Newnode(int &x,int c,int f){ 81 x=++top; 82 L = R = 0; 83 pre[x] = f; 84 sz[x]=1; 85 lazy[x]=0; 86 val[x] = c; 87 sum[x]=c; 88 } 89 inline void init(){ 90 ch[0][0]=ch[0][1]=pre[0]=sz[0]=0; 91 rt=top=0; 92 Newnode(rt,-1,0); 93 Newnode(ch[rt][1],-1,rt); 94 sz[rt]=2; 95 built(KT,1,n,ch[rt][1]); 96 up(ch[rt][1]); 97 up(rt); 98 } 99 /*void BulidTree(int &x,int l,int r,int father){ 100 if(l>r) 101 return; 102 int mid=(l+r)/2; 103 Newnode(x,a[mid],father); 104 if(l<mid) 105 BulidTree(ch[x][0],l,mid-1,x); 106 if(r>mid) 107 BulidTree(ch[x][1],mid+1,r,x); 108 up(x); 109 }*/ 110 void built(int &x,int l,int r,int father) 111 { 112 if(l>r) 113 return ; 114 int mid=(l+r)/2; 115 Newnode(x,a[mid],father); 116 if(l<mid) 117 built(ch[x][0],l,mid-1,x); 118 if(r>mid) 119 built(ch[x][1],mid+1,r,x); 120 up(x); 121 } 122 void Update() 123 { 124 int l,r,c; 125 scanf("%d%d%d",&l,&r,&c); 126 RTO(l-1,0); 127 RTO(r+1,rt); 128 lazy[KT]+=c; 129 sum[KT]+=c*sz[KT]; 130 } 131 void ask() 132 { 133 int l,r; 134 scanf("%d%d",&l,&r); 135 RTO(l-1,0); 136 RTO(r+1,rt); 137 printf("%lld ",sum[KT]); 138 } 139 int val[maxn]; 140 }spt; 141 int main() 142 { 143 int m; 144 scanf("%d%d",&n,&m); 145 for(ll i=1;i<=n;i++) 146 scanf("%d",&a[i]); 147 spt.init(); 148 for(ll i=1;i<=m;i++) 149 { 150 char x; 151 scanf(" %c",&x); 152 if(x=='Q') 153 spt.ask(); 154 else 155 spt.Update(); 156 } 157 return 0; 158 }
对于建树时使用的类似线段树的写法让我又对splay了解了许多。。。