給一個數列,初始時爲 1, 2, 3, ..., n,如今有兩種共 m 個操做php
操做1. CUT a b c 表示把數列中第 a 個到第 b 個從原數列中刪除獲得一個新數列,並將它添加到新數列中第 c 個數的後面ios
操做2. FLIP a b 表示把數列中第 a 個數到第 b 個數翻轉ide
通過 m 個操做以後,輸出這個數列ui
1≤n, m≤3*100000spa
這題也很差用線段樹作,用 Splay 很快就搞出來了code
對於"操做1. CUT a b c" ,只須要將 a-1 旋轉到根,b+1旋轉成 a-1 的子樹,那麼 [a, b] 之間的樹變成了 b+1 的左子樹,將整個子樹從原樹中刪去,並把 b+1 旋轉到根。以後把 c 旋轉到根,c+1 旋轉成 c 的子樹,再把剛纔刪掉的子樹添加到 c+1 的左子樹上(沒添加以前,c+1 的左子樹必然爲空)blog
對於「操做2. FLIP a b」,只須要給樹中每一個節點一個 rev 標記表示是否須要翻轉以該節點爲根的子樹中序遍歷所得的數列,和線段樹差很少的使用懶操做就好了get
仍是那些細節問題,在何時 pushDown,何時 pushUp,寫代碼的時候必定要想清楚cmd
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <queue> 5 6 using namespace std; 7 8 const int N=300005, INF=0x7fffffff; 9 10 struct Splay_Tree { 11 struct Node { 12 int val, Size, son[2]; 13 bool rev; 14 inline void init(int _val) { 15 val=_val, Size=1; 16 son[0]=son[1]=rev=0; 17 } 18 } T[N]; 19 int fa[N], root; 20 queue <int> ans; 21 22 inline void pushUp(int x) { 23 T[x].Size=1; 24 if(T[x].son[0]) T[x].Size+=T[T[x].son[0]].Size; 25 if(T[x].son[1]) T[x].Size+=T[T[x].son[1]].Size; 26 } 27 28 inline void pushDown(int x) { 29 if(!T[x].rev) return; 30 if(T[x].son[0]) T[T[x].son[0]].rev^=1; 31 if(T[x].son[1]) T[T[x].son[1]].rev^=1; 32 swap(T[x].son[0], T[x].son[1]); 33 T[x].rev=0; 34 } 35 36 void Rotate(int x, int kind) { 37 int y=fa[x], z=fa[y]; 38 pushDown(y), pushDown(x); 39 T[y].son[!kind]=T[x].son[kind], fa[T[x].son[kind]]=y; 40 T[x].son[kind]=y, fa[y]=x; 41 T[z].son[T[z].son[1]==y]=x, fa[x]=z; 42 pushUp(y); 43 } 44 45 void Splay(int x, int goal) { 46 if(x==goal) return; 47 while(fa[x]!=goal) { 48 int y=fa[x], z=fa[y]; 49 int rx=T[y].son[0]==x, ry=T[z].son[0]==y; 50 if(z==goal) Rotate(x, rx); 51 else { 52 if(rx==ry) Rotate(y, ry); 53 else Rotate(x, rx); 54 Rotate(x, ry); 55 } 56 } 57 pushUp(x); 58 if(goal==0) root=x; 59 } 60 61 int Select(int pos, int goal) { 62 int u=root; 63 pushDown(u); 64 while(T[T[u].son[0]].Size!=pos) { 65 if(T[T[u].son[0]].Size>pos) u=T[u].son[0]; 66 else { 67 pos-=T[T[u].son[0]].Size+1; 68 u=T[u].son[1]; 69 } 70 pushDown(u); 71 } 72 Splay(u, goal); 73 return u; 74 } 75 76 void Cut(int L, int R, int pos) { 77 int u=Select(L-1, 0), v=Select(R+1, u); 78 int x=T[v].son[0]; 79 fa[x]=0, T[v].son[0]=0; 80 Splay(v, 0); 81 u=Select(pos, 0), v=Select(pos+1, u); 82 T[v].son[0]=x, fa[x]=v; 83 Splay(x, 0); 84 } 85 86 void Reverse(int L, int R) { 87 int u=Select(L-1, 0), v=Select(R+1, u); 88 T[T[v].son[0]].rev^=1; 89 } 90 91 void DFS(int u) { 92 pushDown(u); 93 if(T[u].son[0]) DFS(T[u].son[0]); 94 ans.push(T[u].val); 95 if(T[u].son[1]) DFS(T[u].son[1]); 96 } 97 98 void Display(int n) { 99 while(!ans.empty()) ans.pop(); 100 DFS(root); 101 for(int cnt=0, x; cnt<n; cnt++, ans.pop()) { 102 for(x=ans.front(); x==-INF; ans.pop(), x=ans.front()); 103 printf("%d", x); 104 if(cnt+1==n) printf("\n"); 105 else printf(" "); 106 } 107 } 108 109 int build(int L, int R) { 110 if(L>R) return 0; 111 if(L==R) return L; 112 int mid=(L+R)>>1, sL, sR; 113 T[mid].son[0]=sL=build(L, mid-1); 114 T[mid].son[1]=sR=build(mid+1, R); 115 fa[sL]=fa[sR]=mid; 116 pushUp(mid); 117 return mid; 118 } 119 120 void init(int n) { 121 T[0].init(-INF), T[1].init(-INF), T[n+2].init(-INF); 122 for(int i=2; i<=n+1; i++) T[i].init(i-1); 123 root=build(1, n+2); 124 T[0].Size=0, T[0].son[1]=root, fa[root]=0, fa[0]=0; 125 } 126 } hehe; 127 int n, m; 128 char cmd[10]; 129 130 int main() { 131 // freopen("in", "r", stdin); 132 while(scanf("%d%d",&n, &m), n!=-1 || m!=-1) { 133 hehe.init(n); 134 for(int i=0, a, b, c; i<m; i++) { 135 scanf("%s", cmd); 136 if(cmd[0]=='C') { 137 scanf("%d%d%d", &a, &b, &c); 138 hehe.Cut(a, b, c); 139 } 140 else { 141 scanf("%d%d", &a, &b); 142 hehe.Reverse(a, b); 143 } 144 } 145 hehe.Display(n); 146 } 147 return 0; 148 }
HDU 3487 Play with Chainstring