HDU1890 Robotic Sort Splay tree反转,删除

  题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1890

  题目中涉及数的反转和删除操作,需要用Splay tree来实现。首先对数列排序,得到每个数在数列中的下标x。Splay tree的每个节点标记以它为根的子树是否需要反转,用到懒惰操作,保证nlogn,在每次操作的时候Push_Down()和Push_Up。在建树的时候是数的下标为节点标号建立数,如果要询问数num[i],则把num[i]在数列中的下标旋转到根节点root,size[ch[root][0]]+已经排好序的数的数目就是答案。注意,这里因为涉及到数的反转操作,因此在Splay()操作的时候,应该先Push_Down(),然后再判断旋转操作。。

  1 //STATUS:C++_AC_256MS_2700KB

  2 #include <functional>

  3 #include <algorithm>

  4 #include <iostream>

  5 //#include <ext/rope>

  6 #include <fstream>

  7 #include <sstream>

  8 #include <iomanip>

  9 #include <numeric>

 10 #include <cstring>

 11 #include <cassert>

 12 #include <cstdio>

 13 #include <string>

 14 #include <vector>

 15 #include <bitset>

 16 #include <queue>

 17 #include <stack>

 18 #include <cmath>

 19 #include <ctime>

 20 #include <list>

 21 #include <set>

 22 #include <map>

 23 using namespace std;

 24 //using namespace __gnu_cxx;

 25 //define

 26 #define pii pair<int,int>

 27 #define mem(a,b) memset(a,b,sizeof(a))

 28 #define lson l,mid,rt<<1

 29 #define rson mid+1,r,rt<<1|1

 30 #define PI acos(-1.0)

 31 //typedef

 32 typedef __int64 LL;

 33 typedef unsigned __int64 ULL;

 34 //const

 35 const int N=100010;

 36 const int INF=0x3f3f3f3f;

 37 const int MOD=100000,STA=8000010;

 38 const LL LNF=1LL<<60;

 39 const double EPS=1e-8;

 40 const double OO=1e15;

 41 const int dx[4]={-1,0,1,0};

 42 const int dy[4]={0,1,0,-1};

 43 const int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};

 44 //Daily Use ...

 45 inline int sign(double x){return (x>EPS)-(x<-EPS);}

 46 template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}

 47 template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}

 48 template<class T> inline T lcm(T a,T b,T d){return a/d*b;}

 49 template<class T> inline T Min(T a,T b){return a<b?a:b;}

 50 template<class T> inline T Max(T a,T b){return a>b?a:b;}

 51 template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);}

 52 template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);}

 53 template<class T> inline T Min(T a,T b,T c,T d){return min(min(a, b),min(c,d));}

 54 template<class T> inline T Max(T a,T b,T c,T d){return max(max(a, b),max(c,d));}

 55 //End

 56 

 57 #define Key_value ch[ch[root][1]][0]

 58 int pre[N],ch[N][2];  //分别表示父结点,键值,左右孩子(0为左孩子,1为右孩子),根结点,结点数量

 59 int sz[N],st[N];   //子树规模,内存池

 60 int root,tot,top;   //根节点,根节点数量,内存池容量

 61 //题目特定数据

 62 struct Node{

 63     int num,idx;

 64 }nod[N];

 65 bool rev[N];

 66 int n;

 67 //debug部分copy from hh

 68 void Treaval(int x) {

 69     if(x) {

 70         Treaval(ch[x][0]);

 71         printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d rev = %2d\n",x,ch[x][0],ch[x][1],pre[x],sz[x],rev[x]);

 72         Treaval(ch[x][1]);

 73     }

 74 }

 75 void debug() {printf("%d\n",root);Treaval(root);}

 76 //以上Debug

 77 //新建一个结点

 78 void NewNode(int &x,int fa,int k)

 79 {

 80  //   if(top)x=st[--top];

 81  //   else x=++tot;

 82     x=k;

 83     pre[x]=fa;

 84     sz[x]=1;

 85     rev[x]=0;

 86     ch[x][0]=ch[x][1]=0;  //左右孩子为空

 87 }

 88 

 89 void Push_Up(int x)

 90 {

 91     sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;

 92 }

 93 

 94 void Push_Down(int x)

 95 {

 96     if(rev[x]){

 97         rev[ch[x][0]]^=1;

 98         rev[ch[x][1]]^=1;

 99         swap(ch[x][0],ch[x][1]);

100         rev[x]=0;

101     }

102 }

103 //旋转,kind为1为右旋,kind为0为左旋

104 void Rotate(int x,int kind)

105 {

106     int y=pre[x],z=pre[y];

107     Push_Down(y);

108     Push_Down(x);  //先把y的标记向下传递,再把x的标记往下传递

109     //类似SBT,要把其中一个分支先给父节点

110     ch[y][!kind]=ch[x][kind];

111     pre[ch[x][kind]]=y;

112     //如果父节点不是根结点,则要和父节点的父节点连接起来

113     if(z)ch[z][ch[z][1]==y]=x;

114     pre[x]=z;

115     ch[x][kind]=y;

116     pre[y]=x;

117     Push_Up(y);  //维护y结点,不要维护x节点,x节点会再次Push_Down,最后维护一下x节点即可

118 }

119 //Splay调整,将根为r的子树调整为goal

120 void Splay(int x,int goal)

121 {

122     int y,z,kind;

123     while(pre[x]!=goal){

124         //父节点即是目标位置,goal为0表示,父节点就是根结点

125         y=pre[x];

126         Push_Down(pre[y]);Push_Down(y);Push_Down(x);   //设计到反转操作,要先更新,然后在判断!!

127         if(pre[y]==goal){

128             Rotate(x,ch[y][0]==x);

129         }

130         else {

131             kind=ch[pre[y]][0]==y;

132             //两个方向不同,则先左旋再右旋

133             if(ch[y][kind]==x){

134                 Rotate(x,!kind);

135                 Rotate(x,kind);

136             }

137             //两个方向相同,相同方向连续两次

138             else {

139                 Rotate(y,kind);

140                 Rotate(x,kind);

141             }

142         }

143     }

144     //更新根结点

145     Push_Up(x);

146     if(goal==0)root=x;

147 }

148 //建树,中间结点先建立,然后分别对区间两端在左右子树建立

149 void BuildTree(int &x,int l,int r,int fa)

150 {

151     if(l>r)return;

152     int mid=(l+r)>>1;

153     NewNode(x,fa,mid);

154     BuildTree(ch[x][0],l,mid-1,x);

155     BuildTree(ch[x][1],mid+1,r,x);

156     Push_Up(x);

157 }

158 

159 int cmp(Node a,Node b)

160 {

161     return a.num!=b.num?a.num<b.num:a.idx<b.idx;

162 }

163 

164 void Init()

165 {

166     root=tot=top=0;

167     ch[root][0]=ch[root][1]=pre[0]=sz[0]=rev[0]=0;

168 

169     for(int i=1;i<=n;i++){

170         scanf("%d",&nod[i].num);

171         nod[i].idx=i;

172     }

173     sort(nod+1,nod+n+1,cmp);

174     BuildTree(root,1,n,0);

175 }

176 

177 int Get_Max(int x)

178 {

179     Push_Down(x);

180     while(ch[x][1]){

181         x=ch[x][1];

182         Push_Down(x);

183     }

184     return x;

185 }

186 

187 void Remove()

188 {

189     if(ch[root][0]==0){

190         root=ch[root][1];

191         pre[root]=0;

192     }

193     else {

194         int x=Get_Max(ch[root][0]);

195         Splay(x,root);

196         ch[x][1]=ch[root][1];

197         pre[ch[root][1]]=x;

198         root=x;

199         pre[root]=0;

200         Push_Up(root);

201     }

202 }

203 

204 int main()

205 {

206  //   freopen("in.txt","r",stdin);

207     int i,j;

208     while(~scanf("%d",&n) && n)

209     {

210         Init();

211         for(i=1;i<n;i++){

212             Splay(nod[i].idx,0);

213             rev[ch[root][0]]^=1;

214             printf("%d ",i+sz[ch[root][0]]);

215             Remove();

216         }

217         printf("%d\n",n);

218     }

219     return 0;

220 }

 

你可能感兴趣的:(robot)