1. 程式人生 > >BZOJ 3223 Tyvj 1729 文藝平衡樹

BZOJ 3223 Tyvj 1729 文藝平衡樹

color result merge center img hide rip 至少 print

3223: Tyvj 1729 文藝平衡樹

Description

您需要寫一種數據結構(可參考題目標題),來維護一個有序數列,其中需要提供以下操作:翻轉一個區間,例如原有序序列是5 4 3 2 1,翻轉區間是[2,4]的話,結果是5 2 3 4 1

Input

第一行為n,m n表示初始序列有n個數,這個序列依次是(1,2……n-1,n) m表示翻轉操作次數
接下來m行每行兩個數[l,r] 數據保證 1<=l<=r<=n

Output

輸出一行n個數字,表示原始序列經過m次變換後的結果

Sample Input

5 3
1 3
1 3
1 4

Sample Output

4 3 2 1 5

HINT

N,M<=100000


  為了調出一個正常的splay,實在是調了太久太久。

  不過至少調出來了嘛!?

  就是最普通的平衡樹,而且此題還不用insert和remove。所以,就是build,splay,merge和split,再加上rev標記和pushdown。splay的cmp與treap的cmp不同,treap的cmp是按值的,而splay是按siz的(因為是下標標號)。所以說,insert的時候有k還有x(x似乎無用)。額,似乎很顯然。而進入ch[1]的時候,一定不能忘了先把k減下去。

  關於splay操作,按理是雙旋的,但我寫了隨機比較單旋和雙旋,似乎沒有什麽大區別。事實似乎也是這樣。

splay單旋 2776 kb 2184 ms 2351 B
splay雙旋 2776 kb 2004 ms 2559 B

  但是,確實有理論證明。雙旋可以有效地“本質化地”優化樹的形態。

  關於split和merge,劉汝佳建議,使用虛擬節點,但本人嫌麻煩,只需要再特判一下。因為split是把樹o的前k個分入left,之後的分入right,當k為0時就不用旋也不能旋了。而且merge是把left變成“右空樹”再連上 right,當left為null時就不用旋也不能旋了。第一次感覺null這麽方便。

  而rev標記,是只要訪問就該pushdown了,無論是insert,remove,還是splay,print,如果忘了會出大事。

  而maintain(update)呢?只要樹形態變化就應該做。也就是build,insert,remove,rotate,還有merge和split。註意splay內部並不需要maintain,因為splay本身不過是一堆rotate。而remove時,maintain需要註意判斷null,不然一旦亂搞,這棵樹就完了。而null時,一般都是o->ch[0]==null&&o->ch[1]==null,在d==-1時if(o->ch[0]==null) o=o->ch[1];這樣是很明顯的。

  我們在進行區間操作時,一般都會把操作的區間split出來,防止其他元素糾結,之後在merge回去。此題無需關心insert,但是如果有insert,插入之後還應splay一下,只有這樣才能擺脫鏈的詛咒。

  第一次敲splay,真的很苦啊。

技術分享
 1 /**************************************************************
 2     Problem: 3223
 3     User: Doggu
 4     Language: C++
 5     Result: Accepted
 6     Time:2184 ms
 7     Memory:2776 kb
 8 ****************************************************************/
 9  
10 #include <cstdio>
11 #include <algorithm>
12 const int N = 100010;
13 struct Node {
14     int val, siz;
15     bool rev;
16     Node *ch[2];
17     int cmp(int k) {
18     if(k<=ch[0]->siz) return 0;
19     if(k<=ch[0]->siz+1) return -1;
20     return 1;
21     }
22     void pushdown() {if(rev) {
23     std::swap(ch[0],ch[1]);
24     ch[0]->rev^=1;
25     ch[1]->rev^=1;
26     rev = 0;    
27     }}
28     void maintain() {
29     siz=ch[0]->siz+ch[1]->siz+1;
30     }
31 }pool[N], *tail=pool, *null=pool, *root;
32 //int aa[N];
33 void rotate(Node *&o,int d) {
34     Node *k=o->ch[d^1];o->ch[d^1]=k->ch[d];k->ch[d]=o;
35     o->maintain();k->maintain();o=k;
36 }
37 Node *build(int lf,int rg) {
38     Node *o=++tail;
39     int mid=(lf+rg)>>1;
40     o->val=mid;//aa[mid];
41     o->ch[0]=(lf<=mid-1)?build(lf,mid-1):null;
42     o->ch[1]=(mid+1<=rg)?build(mid+1,rg):null;
43     o->maintain();
44     return o;
45 }
46 void splay(Node *&o,int k) {
47     o->pushdown();
48     int d=o->cmp(k);
49     if(d==1) k-=o->ch[0]->siz+1;
50     if(d!=-1) splay(o->ch[d],k), rotate(o,d^1);
51 }
52 Node *merge(Node *left,Node *right) {
53     if(left==null) return right;
54     splay(left,left->siz);
55     left->ch[1]=right;left->maintain();
56     return left;
57 }
58 void split(Node *o,int k,Node *&left,Node *&right) {
59     if(k==0) left=null, right=o;
60     else {
61     splay(o,k);
62     left=o;right=o->ch[1];
63     o->ch[1]=null;left->maintain();
64     }
65 }
66 void print(Node *o) {
67     if(o==null) return ;
68     o->pushdown();
69     print(o->ch[0]);
70     printf("%d ",o->val);
71     print(o->ch[1]);
72 }
73 int main() {
74     null->ch[0]=null->ch[1]=null;
75     int n, q, lf, rg;
76     scanf("%d%d",&n,&q);
77     //for( int i = 1; i <= n; i++ ) scanf("%d",&aa[i]);
78     root=build(1,n);
79     //printf("ROOT_SEQ:");print(root);printf("\n");
80     while(q--) {
81     scanf("%d%d",&lf,&rg);
82     Node *left, *mid, *right, *o;
83     split(root,rg,mid,right);
84     split(mid,lf-1,left,mid);
85     //printf("LEFT_SEQ:");print(left);printf("\n");
86     //printf("MID_SEQ:");print(mid);printf("\n");
87     //printf("RIGHT_SEQ:");print(right);printf("\n");
88     mid->rev^=1;
89     root=merge(merge(left,mid),right);
90     //printf("ROOT_SEQ:");print(root);printf("\n");
91     }
92     print(root);printf("\n");
93     return 0;
94 }
95 
單旋 技術分享
  1 /**************************************************************
  2     Problem: 3223
  3     User: Doggu
  4     Language: C++
  5     Result: Accepted
  6     Time:2004 ms
  7     Memory:2776 kb
  8 ****************************************************************/
  9  
 10 #include <cstdio>
 11 #include <algorithm>
 12 const int N = 100010;
 13 struct Node {
 14     int val, siz;
 15     bool rev;
 16     Node *ch[2];
 17     int cmp(int k) {
 18     if(k<=ch[0]->siz) return 0;
 19     if(k<=ch[0]->siz+1) return -1;
 20     return 1;
 21     }
 22     void pushdown() {if(rev) {
 23     std::swap(ch[0],ch[1]);
 24     ch[0]->rev^=1;
 25     ch[1]->rev^=1;
 26     rev = 0;    
 27     }}
 28     void maintain() {
 29     siz=ch[0]->siz+ch[1]->siz+1;
 30     }
 31 }pool[N], *tail=pool, *null=pool, *root;
 32 //int aa[N];
 33 void rotate(Node *&o,int d) {
 34     Node *k=o->ch[d^1];o->ch[d^1]=k->ch[d];k->ch[d]=o;
 35     o->maintain();k->maintain();o=k;
 36 }
 37 Node *build(int lf,int rg) {
 38     Node *o=++tail;
 39     int mid=(lf+rg)>>1;
 40     o->val=mid;//aa[mid];
 41     o->ch[0]=(lf<=mid-1)?build(lf,mid-1):null;
 42     o->ch[1]=(mid+1<=rg)?build(mid+1,rg):null;
 43     o->maintain();
 44     return o;
 45 }
 46 void splay(Node *&o,int k) {
 47     o->pushdown();
 48     int d=o->cmp(k);
 49     if(d==1) k-=o->ch[0]->siz+1;
 50     if(d!=-1) {
 51     Node *p=o->ch[d];
 52     p->pushdown();
 53     int d2=p->cmp(k);
 54     int k2=(d2==0?k:k-p->ch[0]->siz-1);
 55     if(d2!=-1) {
 56         splay(p->ch[d2],k2);
 57         if(d==d2) rotate(o,d^1);else rotate(o->ch[d],d);
 58     }
 59     rotate(o,d^1);
 60     }
 61 }
 62 Node *merge(Node *left,Node *right) {
 63     if(left==null) return right;
 64     splay(left,left->siz);
 65     left->ch[1]=right;left->maintain();
 66     return left;
 67 }
 68 void split(Node *o,int k,Node *&left,Node *&right) {
 69     if(k==0) left=null, right=o;
 70     else {
 71     splay(o,k);
 72     left=o;right=o->ch[1];
 73     o->ch[1]=null;left->maintain();
 74     }
 75 }
 76 void print(Node *o) {
 77     if(o==null) return ;
 78     o->pushdown();
 79     print(o->ch[0]);
 80     printf("%d ",o->val);
 81     print(o->ch[1]);
 82 }
 83 int main() {
 84     null->ch[0]=null->ch[1]=null;
 85     int n, q, lf, rg;
 86     scanf("%d%d",&n,&q);
 87     //for( int i = 1; i <= n; i++ ) scanf("%d",&aa[i]);
 88     root=build(1,n);
 89     //printf("ROOT_SEQ:");print(root);printf("\n");
 90     while(q--) {
 91     scanf("%d%d",&lf,&rg);
 92     Node *left, *mid, *right, *o;
 93     split(root,rg,mid,right);
 94     split(mid,lf-1,left,mid);
 95     //printf("LEFT_SEQ:");print(left);printf("\n");
 96     //printf("MID_SEQ:");print(mid);printf("\n");
 97     //printf("RIGHT_SEQ:");print(right);printf("\n");
 98     mid->rev^=1;
 99     root=merge(merge(left,mid),right);
100     //printf("ROOT_SEQ:");print(root);printf("\n");
101     }
102     print(root);printf("\n");
103     return 0;
104 }
105 
雙旋

BZOJ 3223 Tyvj 1729 文藝平衡樹