1. 程式人生 > >洛谷 P3391 【模板】文藝平衡樹(Splay)

洛谷 P3391 【模板】文藝平衡樹(Splay)

模板 class opera void 直接 曾經 維護 如果 spa

先記一發非旋treap,splay什麽的以後再說

基本就是正常的非旋treap維護序列加上一個flip標記,如果某個節點flip為true表示以它為根的子樹需要一次翻轉。類似線段樹lazytag

每次可能要修改某個節點o的任意ch之前,都對o進行一次pushdown。(就是split和merge中)

pushdown的操作是交換o的兩個子節點,再將兩個子節點的flip標記異或1。

每次進行翻轉操作(翻轉[l,r]),就把整個序列split成三段[1,l-1],[l,r],[r+1,size]。然後直接將中間一段的根節點的flip標記異或1,再merge回去就行了。

曾經錯誤:72行兩個語句反了;實際上flip不需要修改split和merge,不要多此一舉

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<ctime>
  4 using namespace std;
  5 template<typename T>
  6 class MyVec
  7 {
  8 private:
  9     static const int M_SIZE=200001;
 10     int rand1()
 11     {
 12         static int x=471;
 13         return
x=(48271LL*x+1)%2147483647; 14 } 15 public: 16 struct Node 17 { 18 Node(){} 19 Node* ch[2]; 20 int r; 21 bool flip; 22 //表示該節點的所有子節點需要flip 23 T v; 24 int size; 25 void upd() 26 { 27 size=1
+(ch[0]?ch[0]->size:0)+(ch[1]?ch[1]->size:0); 28 } 29 void pushdown() 30 { 31 if(flip) 32 { 33 Node* t=ch[0];ch[0]=ch[1];ch[1]=t; 34 if(ch[0]) (ch[0]->flip)^=1; 35 if(ch[1]) (ch[1]->flip)^=1; 36 flip=0; 37 } 38 } 39 }nodes[M_SIZE]; 40 private: 41 Node* root; 42 Node* que[M_SIZE]; 43 int que_top; 44 Node* getnode() 45 { 46 return que[que_top--]; 47 } 48 void delnode(Node* x) 49 { 50 que[++que_top]=x; 51 } 52 Node* merge(Node* a,Node* b) 53 { 54 if(a==NULL) return b; 55 if(b==NULL) return a; 56 if(a->r < b->r) 57 { 58 a->pushdown();a->ch[1]=merge(a->ch[1],b);a->upd(); 59 return a; 60 } 61 else 62 { 63 b->pushdown();b->ch[0]=merge(a,b->ch[0]);b->upd(); 64 return b; 65 } 66 } 67 typedef pair<Node*,Node*> P; 68 P split(Node* a,int n) 69 { 70 if(a==NULL) return P(NULL,NULL); 71 P y; 72 a->pushdown();int s=a->ch[0] ? a->ch[0]->size : 0; 73 if(s>=n) 74 { 75 y=split(a->ch[0],n); 76 a->ch[0]=y.second;a->upd(); 77 y.second=a; 78 } 79 else 80 { 81 y=split(a->ch[1],n-s-1); 82 a->ch[1]=y.first;a->upd(); 83 y.first=a; 84 } 85 return y; 86 } 87 Node* kth(Node* o,int k) 88 { 89 if(o==NULL||k<=0||k > o->size) return NULL; 90 P y=split(root,k-1); 91 P y2=split(y.second,1); 92 root=merge(merge(y.first,y2.first),y2.second); 93 return y2.first; 94 } 95 void erase(Node* &o,int k) 96 { 97 if(o==NULL||k<=0||k > o->size) return; 98 P y=split(root,k-1); 99 P y2=split(y.second,1); 100 delnode(y2.first); 101 root=merge(y.first,y2.second); 102 } 103 public: 104 //在第k個之前插入 105 void insert(int k,const T& x) 106 { 107 Node* t=getnode(); 108 t->ch[0]=t->ch[1]=NULL;t->r=rand1();t->v=x;t->flip=0;t->upd(); 109 P y=split(root,k-1); 110 root=merge(merge(y.first,t),y.second); 111 } 112 MyVec() 113 { 114 que_top=M_SIZE-1; 115 for(int i=0;i<M_SIZE;i++) que[i]=nodes+i; 116 root=NULL; 117 } 118 void push_back(const T& x) 119 { 120 insert(size()+1,x); 121 } 122 void pop_back() 123 { 124 erase(root,root->size); 125 } 126 void push_front(const T& x) 127 { 128 insert(1,x); 129 } 130 void pop_front() 131 { 132 erase(root,1); 133 } 134 Node* find_by_order(int k) 135 { 136 return kth(root,k); 137 } 138 T& operator[](int k) 139 { 140 return kth(root,k)->v; 141 } 142 void erase(int k) 143 { 144 erase(root,k); 145 } 146 int size() 147 { 148 return root ? root->size : 0; 149 } 150 //翻轉[l,r] 151 void flip(int l,int r) 152 { 153 P y=split(root,l-1); 154 P y2=split(y.second,r-l+1); 155 y2.first->flip^=1; 156 root=merge(merge(y.first,y2.first),y2.second); 157 } 158 }; 159 MyVec<int> x; 160 int n,m,l,r; 161 int main() 162 { 163 int i; 164 scanf("%d%d",&n,&m); 165 for(i=1;i<=n;i++) 166 x.push_back(i); 167 while(m--) 168 { 169 scanf("%d%d",&l,&r); 170 x.flip(l,r); 171 } 172 for(i=1;i<=n;i++) 173 printf("%d ",x[i]); 174 return 0; 175 }

洛谷 P3391 【模板】文藝平衡樹(Splay)