HDU 3487 Play with Chain(Splay)

题目大意

给一个数列,初始时为 1, 2, 3, ..., n,现在有两种共 m 个操作

  操作1. CUT a b c 表示把数列中第 a 个到第 b 个从原数列中删除得到一个新数列,并将它添加到新数列中第 c 个数的后面

  操作2. FLIP a b 表示把数列中第 a 个数到第 b 个数翻转

经过 m 个操作之后,输出这个数列

1≤n, m≤3*100000

做法分析

这题也不好用线段树做,用 Splay 很快就搞出来了

对于"操作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 的左子树必然为空)

对于“操作2. FLIP a b”,只需要给树中每个节点一个 rev 标记表示是否需要翻转以该节点为根的子树中序遍历所得的数列,和线段树差不多的使用懒操作就行了

还是那些细节问题,在什么时候 pushDown,什么时候 pushUp,写代码的时候一定要想清楚

参考代码

  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("
");
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

题目链接 & AC 通道

HDU 3487 Play with Chain

原文地址:https://www.cnblogs.com/zhj5chengfeng/p/3271347.html