[luogu P3391] 文藝平衡樹
阿新 • • 發佈:2017-11-25
hid clu 模板 搜索樹 open namespace 接下來 getchar() play
[luogu P3391] 文藝平衡樹
題目背景
這是一道經典的Splay模板題——文藝平衡樹。
題目描述
您需要寫一種數據結構(可參考題目標題),來維護一個有序數列,其中需要提供以下操作:翻轉一個區間,例如原有序序列是5 4 3 2 1,翻轉區間是[2,4]的話,結果是5 2 3 4 1
輸入輸出格式
輸入格式:
第一行為n,m n表示初始序列有n個數,這個序列依次是(1,2, \cdots n-1,n)(1,2,?n−1,n) m表示翻轉操作次數
接下來m行每行兩個數 [l,r][l,r] 數據保證 1 \leq l \leq r \leq n1≤l≤r≤n
輸出格式:
輸出一行n個數字,表示原始序列經過m次變換後的結果。
輸入輸出樣例
輸入樣例#1: 復制5 3 1 3 1 3 1 4
輸出樣例#1: 復制4 3 2 1 5
說明
n,m≤100000
上次就很想寫了,splay的妙用。
splay能做到一般的平衡樹做不到的東西——維護序列。
為什麽一般的平衡樹做不到?正是因為splaytree的核心操作——splay。
這個log級別的操作能將一個連續的子序列搞到一棵子樹中。
比如要維護[l,r],則調用一下splay(find(l-1),0),splay(find(r+1),root)。
但是要註意一下,對於這題,我們需要一個節點在當前序列的排名和初始位置(即權值)。
一個節點的排名是它的左子樹大小+1,初始位置是不變的。
對於這題,還有一個巧妙的地方,就是reverse操作。
這裏用到了和線段樹類似的lazy打標記,延遲下傳的思想。還是很厲害的。
輸出的話,根據二叉搜索樹的性質,直接中序遍歷。
code:
1 #include <cstdio> 2 #include <iostream> 3 4 void OJ_file() { 5 #ifndef ONLINE_JUDGE 6View Codefreopen("in.txt","r",stdin); 7 freopen("out.txt","w",stdout); 8 #endif 9 } 10 namespace fastIO { 11 #define puc(c) putchar(c) 12 inline int read() { 13 int x=0,f=1; char ch=getchar(); 14 while (ch<‘0‘||ch>‘9‘) { 15 if (ch==‘-‘) f=-f; 16 ch=getchar(); 17 } 18 while (ch>=‘0‘&&ch<=‘9‘) { 19 x=(x<<3)+(x<<1)+ch-‘0‘; 20 ch=getchar(); 21 } 22 return x*f; 23 } 24 int cnt,w[20]; 25 template <class T> inline void write(T x) { 26 if (x==0) { 27 puc(‘0‘); return; 28 } 29 if (x<0) x=-x,puc(‘-‘); 30 for (cnt=0; x; x/=10) w[++cnt]=x%10; 31 for (; cnt; --cnt) puc(w[cnt]+48); 32 } 33 inline void newblank() { 34 puc(‘ ‘); 35 } 36 } using namespace fastIO; 37 38 int n,m; 39 #define SplayTree node 40 struct SplayTree { 41 int v,k; bool r; 42 node* c[3]; 43 node () { 44 v=k=r=0; 45 c[0]=c[1]=c[2]=0; 46 } 47 }*ro; 48 void newnode (node* &x,int k) { 49 x=new node(),x->v=1,x->k=k; 50 } 51 void refresh (node* x) { 52 x->v=1; 53 if (x->c[0]) x->v+=x->c[0]->v; 54 if (x->c[1]) x->v+=x->c[1]->v; 55 } 56 void transfer (node* x) { 57 if (x->r) { 58 if (x->c[0]) x->c[0]->r^=1; 59 if (x->c[1]) x->c[1]->r^=1; 60 x->r=0,std::swap(x->c[0],x->c[1]); 61 } 62 } 63 #define M ((l)+(r)>>1) 64 void setup (node* &x,int l,int r) { 65 if (l>r) return; 66 newnode(x,M); 67 setup(x->c[0],l,M-1),setup(x->c[1],M+1,r); 68 if (x->c[0]) x->c[0]->c[2]=x; 69 if (x->c[1]) x->c[1]->c[2]=x; 70 refresh(x); 71 } 72 bool dir (node* x) { 73 if (!x->c[2]) return 0; 74 return x->c[2]->c[1]==x; 75 } 76 void linknode (node* y,node* x,bool p) { 77 if (x) x->c[2]=y; 78 if (y) y->c[p]=x; 79 } 80 void rotate (node* x) { 81 bool p=dir(x); node* y=x->c[2]; 82 linknode(y->c[2],x,dir(y)); 83 linknode(y,x->c[p^1],p); 84 linknode(x,y,p^1); 85 refresh(y),refresh(x); 86 } 87 void splay (node* x,node* an) { 88 if (x->c[2]==an) return; 89 while (x->c[2]!=an) { 90 if (x->c[2]->c[2]==an) { 91 rotate(x); 92 if (!an) ro=x; 93 return; 94 } 95 rotate(dir(x)^dir(x->c[2])?x:x->c[2]); 96 rotate(x); 97 } 98 if (!an) ro=x; 99 } 100 node* find (node* x,int v) { 101 transfer(x); 102 int s=x->c[0]?x->c[0]->v:0; 103 if (v==s) return x; 104 if (v<s+1) return find(x->c[0],v); 105 else return find(x->c[1],v-s-1); 106 } 107 void reverse (int l,int r) { 108 node* q[2]={find(ro,l-1),find(ro,r+1)}; 109 splay(q[0],0),splay(q[1],ro); 110 ro->c[1]->c[0]->r^=1; 111 } 112 void dfs (node* x) { 113 transfer(x); 114 if (x->c[0]) dfs(x->c[0]); 115 if (x->k>=1&&x->k<=n) { 116 write(x->k),newblank(); 117 } 118 if (x->c[1]) dfs(x->c[1]); 119 } 120 int main() { 121 OJ_file(); 122 n=read(),m=read(),ro=0; 123 setup(ro,0,n+1); 124 int l,r; 125 for (; m; --m) { 126 l=read(),r=read(); 127 if (l==r) continue; 128 reverse(l,r); 129 } 130 dfs(ro); 131 return 0; 132 }
[luogu P3391] 文藝平衡樹