题目背景
这是一道经典的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次变换后的结果
输入输出样例
说明
code
1 #include<cstdio> 2 #include<algorithm> 3 4 using namespace std; 5 6 const int N = 500100; 7 int ch[N][2],tag[N],val[N],siz[N],key[N]; 8 int tn,Root,n,m; 9 10 inline char nc() { 11 static char buf[100000],*p1 = buf,*p2 = buf; 12 return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2) ? EOF : *p1++; 13 } 14 inline int read() { 15 int x = 0,f = 1;char ch = nc(); 16 for (; ch<'0'||ch>'9'; ch = nc()) 17 if (ch=='-') f = -1; 18 for (; ch>='0'&&ch<='9'; ch = nc()) 19 x = x*10+ch-'0'; 20 return x * f; 21 } 22 inline void pushup(int x) { 23 siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + 1; 24 } 25 inline void pushdown(int x) { 26 if (tag[x]) { 27 tag[ch[x][0]] ^= 1;tag[ch[x][1]] ^= 1; 28 swap(ch[x][0],ch[x][1]); 29 tag[x] ^= 1; 30 } 31 } 32 inline int makenode(int x) { 33 ++tn;siz[tn] = 1;val[tn] = x;key[tn] = rand();return tn; 34 } 35 int merge(int x,int y) { 36 if (!x || !y) return x + y; 37 pushdown(x);pushdown(y); 38 if (key[x] < key[y]) { 39 ch[x][1] = merge(ch[x][1],y); 40 pushup(x);return x; 41 } 42 else { 43 ch[y][0] = merge(x,ch[y][0]); 44 pushup(y);return y; 45 } 46 } 47 void split(int now,int k,int &x,int &y) { 48 if (!now) x = y = 0; 49 else { 50 pushdown(now); 51 if (k<=siz[ch[now][0]]) 52 y = now,split(ch[now][0],k,x,ch[now][0]); 53 else 54 x = now,split(ch[now][1],k-siz[ch[now][0]]-1,ch[now][1],y); 55 pushup(now); 56 } 57 } 58 inline void rever(int l,int r) { 59 int a,b,c,d; 60 split(Root,r,a,b); 61 split(a,l-1,c,d); 62 tag[d] ^= 1; 63 Root = merge(merge(c,d),b); 64 } 65 void print(int x) { 66 if (!x) return ; 67 pushdown(x); 68 print(ch[x][0]); 69 printf("%d ",val[x]); 70 print(ch[x][1]); 71 } 72 int main() { 73 n = read(),m = read(); 74 for (int i=1; i<=n; ++i) { 75 Root = merge(Root,makenode(i)); 76 } 77 while (m--) { 78 int a = read(),b = read(); 79 rever(a,b); 80 } 81 print(Root); 82 return 0; 83 }
网上学的另一种建树方法:
1 int build(int l,int r) 2 { 3 if (l>r) return 0; 4 int mid=(l+r)>>1,v=mid; 5 int now=makenode(v); 6 ch[now][0]=build(l,mid-1); 7 ch[now][1]=build(mid+1,r); 8 pushup(now); 9 return now; 10 } 11 Root = build(1,n);
虽然可能不满足堆的性质,但是,堆在这个过程中只是调节树的平衡的,所以还是可以过的
板子的发展史。。。
1 #include<cstdio> 2 #include<algorithm> 3 4 using namespace std; 5 6 const int N = 500100; 7 int ch[N][2],tag[N],val[N],siz[N],key[N]; 8 int tn,Root,n,m; 9 10 inline char nc() { 11 static char buf[100000],*p1 = buf,*p2 = buf; 12 return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2) ? EOF : *p1++; 13 } 14 inline int read() { 15 int x = 0,f = 1;char ch = nc(); 16 for (; ch<'0'||ch>'9'; ch = nc()) 17 if (ch=='-') f = -1; 18 for (; ch>='0'&&ch<='9'; ch = nc()) 19 x = x*10+ch-'0'; 20 return x * f; 21 } 22 inline void pushup(int x) { 23 siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + 1; 24 } 25 inline void pushdown(int x) { 26 if (tag[x]) { 27 tag[ch[x][0]] ^= 1;tag[ch[x][1]] ^= 1; 28 swap(ch[x][0],ch[x][1]); 29 tag[x] ^= 1; 30 } 31 } 32 inline int makenode(int x) { 33 ++tn;siz[tn] = 1;val[tn] = x;key[tn] = rand();return tn; 34 } 35 int merge(int x,int y) { 36 if (!x || !y) return x + y; 37 if (key[x] < key[y]) { 38 pushdown(x); 39 ch[x][1] = merge(ch[x][1],y); 40 pushup(x);return x; 41 } 42 else { 43 pushdown(y); 44 ch[y][0] = merge(x,ch[y][0]); 45 pushup(y);return y; 46 } 47 } 48 void split(int now,int k,int &x,int &y) { 49 if (!now) x = y = 0; 50 else { 51 pushdown(now); 52 if (k<=siz[ch[now][0]]) 53 y = now,split(ch[now][0],k,x,ch[now][0]); 54 else 55 x = now,split(ch[now][1],k-siz[ch[now][0]]-1,ch[now][1],y); 56 pushup(now); 57 } 58 } 59 inline void rever(int l,int r) { 60 int a,b,c,d; 61 split(Root,r,a,b); 62 split(a,l-1,c,d); 63 tag[d] ^= 1; 64 Root = merge(merge(c,d),b); 65 } 66 void print(int x) { 67 if (!x) return ; 68 pushdown(x); 69 print(ch[x][0]); 70 printf("%d ",val[x]); 71 print(ch[x][1]); 72 } 73 int main() { 74 n = read(),m = read(); 75 for (int i=1; i<=n; ++i) { 76 Root = merge(Root,makenode(i)); 77 } 78 while (m--) { 79 int a = read(),b = read(); 80 rever(a,b); 81 } 82 print(Root); 83 return 0; 84 }