Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
6 3 4 5 1 6 2 4 3 3 2 1 0
【Sample Output】
4 6 4 5 6 6 4 2 4 4
【题意】
机械臂可以翻转整个数列中连续的某一串序列,要求用这种翻转的方式完成整个数列的排序。
【分析】
排序的方式题目已经给出了,只需要按照要求去模拟即可,而模拟这个过程的方法很重要,时间上还是要求比较严格的。
获取数据之后首先排序一遍,记录下排完序之后每个点原本的位置,这个就是等一下在树中进行操作时需要用到的了。
题目要求的翻转方式是每次刚好将第i个翻转到位,每次翻转之后固定一个数,然后翻转下一个数,直到翻转完全部的数。
只要用splay将每次的目标结点移到根,那么其左子树的大小就是数列中排在它左边的点的个数,也就是题目要求输出的部分。然后翻转整个左子树(将子树的左右儿子交换,递归到底),删除根,就完成了一次操作。
思路很清晰,但是这里遇到的问题是如何翻转左子树,如果每次都手动递归向下翻转所有树的话,时间上必然是要超时的。从线段树中启发,可以用标记的方式标记翻转情况,减少直接操作的次数,用传递标记的方式传下去:
输出结果后,将左子树打上翻转标记,然后删除根。
一个结点翻转标记的传递必须要发生在对其子树进行操作之前,本题中,后续直接操作子树的过程是接下来的删根操作(我的代码中要从左右子树中找前后继)和下一轮将下一个目标移到根的过程。所以要在这两个过程前加入维护的过程。
删根中找前后继因为是从上往下的,刚好可以顺便查看标记情况对子树完成翻转。问题是下一次提升结点到根的时候不能确定上方父节点的标记情况,因此只能从当前结点开始向上查到根,然后从根开始向下回到目标结点,一路查看标记完成翻转维护......这一块我只能想出这个方法了,不知道其他大神有没有什么更好的方法。这里用递归反查结果栈溢出了,只好开了个大数组记录,,,最后提交AC的通过时间也比较长,应该确实是还有更好的方法吧
1 /* *********************************************** 2 MYID : Chen Fan 3 LANG : G++ 4 PROG : HDU1890 5 ************************************************ */ 6 7 #include <iostream> 8 #include <cstdio> 9 #include <cstring> 10 #include <algorithm> 11 12 using namespace std; 13 14 typedef struct nod 15 { 16 int key,num; 17 } node; 18 19 #define MAXN 100010 20 21 node a[MAXN]; 22 int list[MAXN]; 23 24 bool op(node a,node b) 25 { 26 if (a.key==b.key) return a.num<b.num; 27 else return a.key<b.key; 28 } 29 30 int sons[MAXN][2]; 31 int father[MAXN],size[MAXN],data[MAXN]; 32 bool flag[MAXN]; 33 int spt=0,spttail=0; 34 35 void rotate(int x,int w) //rotate(node,0/1) 36 { 37 int y=father[x]; 38 sons[y][1-w]=sons[x][w]; 39 if (sons[x][w]) father[sons[x][w]]=y; 40 41 father[x]=father[y]; 42 if (father[y]) 43 if (y==sons[father[y]][0]) sons[father[y]][0]=x; 44 else sons[father[y]][1]=x; 45 46 sons[x][w]=y; 47 father[y]=x; 48 49 size[x]=size[y]; 50 size[y]=size[sons[y][0]]+size[sons[y][1]]+1; 51 } 52 53 void splay(int x,int y) //splay(node,position) 54 { 55 if (!x) return ; 56 //check(x); 57 while(father[x]!=y) 58 { 59 if (father[father[x]]==y) 60 if (x==sons[father[x]][0]) rotate(x,1); 61 else rotate(x,0); 62 else 63 if (father[x]==sons[father[father[x]]][0]) 64 if (x==sons[father[x]][0]) 65 { 66 rotate(father[x],1); 67 rotate(x,1); 68 } else 69 { 70 rotate(x,0); 71 rotate(x,1); 72 } 73 else 74 if (x==sons[father[x]][1]) 75 { 76 rotate(father[x],0); 77 rotate(x,0); 78 } else 79 { 80 rotate(x,1); 81 rotate(x,0); 82 } 83 } 84 if (!y) spt=x; 85 } 86 87 void insert(int w) //insert(value) 88 { 89 spttail++; 90 data[spttail]=w; 91 size[spttail]=1; 92 sons[spttail][0]=0; 93 sons[spttail][1]=0; 94 flag[spttail]=0; 95 if (!spt) 96 { 97 father[spttail]=0; 98 spt=spttail; 99 } else 100 { 101 int x=spt; 102 while(1) 103 { 104 size[x]++; 105 if (w<data[x]) 106 if (sons[x][0]) x=sons[x][0]; 107 else break; 108 else 109 if (sons[x][1]) x=sons[x][1]; 110 else break; 111 } 112 father[spttail]=x; 113 if (w<data[x]) sons[x][0]=spttail; 114 else sons[x][1]=spttail; 115 splay(spttail,0); 116 } 117 } 118 119 void down(int x) 120 { 121 flag[x]=0; 122 int t=sons[x][1]; 123 sons[x][1]=sons[x][0]; 124 sons[x][0]=t; 125 flag[sons[x][0]]=1-flag[sons[x][0]]; 126 flag[sons[x][1]]=1-flag[sons[x][1]]; 127 } 128 129 void del(int x) //del(number) 130 { 131 splay(x,0); 132 133 int y=sons[x][0]; 134 if (flag[y]) down(y); 135 while(sons[y][1]) 136 { 137 y=sons[y][1]; 138 if (flag[y]) down(y); 139 } 140 141 int z=sons[x][1]; 142 if (flag[z]) down(z); 143 while(sons[z][0]) 144 { 145 z=sons[z][0]; 146 if (flag[z]) down(z); 147 } 148 149 if (y) 150 { 151 splay(y,0); 152 size[y]--; 153 if (z) 154 { 155 splay(z,y); 156 sons[z][0]=0; 157 size[z]--; 158 } else sons[y][1]=0; 159 } else 160 { 161 if (z) 162 { 163 splay(z,0); 164 sons[z][0]=0; 165 size[z]--; 166 } else 167 { 168 spt=0; 169 spttail=0; 170 } 171 } 172 } 173 174 void check(int x) 175 { 176 //if (father[x]) check(father[x]); 177 //if (flag[x]) down(x); 178 int i=0; 179 while (father[x]) 180 { 181 i++; 182 list[i]=x; 183 x=father[x]; 184 } 185 while (i>0) 186 { 187 if (flag[list[i]]) down(list[i]); 188 i--; 189 } 190 } 191 192 int main() 193 { 194 //freopen("1.txt","r",stdin); 195 196 int n; 197 scanf("%d",&n); 198 while(n) 199 { 200 spt=0; 201 spttail=0; 202 for (int i=1;i<=n;i++) 203 { 204 scanf("%d",&a[i].key); 205 a[i].num=i; 206 insert(i); 207 } 208 sort(&a[1],&a[n+1],op); 209 210 for (int i=1;i<=n;i++) 211 { 212 check(a[i].num); 213 splay(a[i].num,0); 214 if (i>1) printf(" "); 215 printf("%d",size[sons[spt][0]]+i); 216 217 flag[sons[spt][0]]=1-flag[sons[spt][0]]; 218 219 del(spt); 220 } 221 222 printf("\n"); 223 scanf("%d",&n); 224 } 225 226 return 0; 227 }
原文:http://www.cnblogs.com/jcf94/p/4335915.html